...

четверг, 28 ноября 2013 г.

Конспекты лекций «Haskell как первый язык программирования». Часть1

image

Привет Habr! Сегодня я достал свои старые лекции по курсу «Haskell как первый язык программирования» Сергея Михайловича Абрамова и попробую максимально доходчиво и с примерами рассказать об этом замечательном языке тем, кто с ним еще не знаком. Рассказ ориентирован на неподготовленного читателя. Так что, даже если вы впервые услышали слово Haskell…
Базовые типы Haskell



Базовые типы языка Haskell — это:

Числа

Логические величины

Символы

Списки

Упорядоченные множества (tuples)

Функции

Числа

Целые:

Integer (-∞,∞)

Int (-2^31, 2^31-1)

В прелюдии (стандартной библиотеке) определенно много полезных функций для целых чисел, в том числе, и преобразование в число с плавающей точкой (fromInt и fromInteger)


Числа с плавающей точкой:

Float (7 знаков после запятой)

Double (16 знаков после запятой)


Логические величины

Bool (True | False)

Операции конъюнкции, дизъюнкции и отрицания (&&, ||, not)


Символы

Char (’a’)

И функции Char в Int и Int в Char (ord, chr)


Списки

Списки могут быть разные:

[Int] — список целых чисел [1,2,3,4]

[Char] — список символов (строка)

[[Int]] — массив

[Float -> Float] — это список функций

и т. д.


Несколько стандартных операций в примерах:

Main> head [1,2,3]

1

Main> tail [1,2,3]

[2,3]

Main> length [True,False]

2

Main> reverse [1,2,3]

[3,2,1]

Main> 0:[1,2,3]

[0,1,2,3]

Main> — строка приглашения в консоли компилятора ghci

«:» — операция присоединения элемента к списку.


Упорядоченные множества

Примеры:

(2.4, ”cat”) (Float, [Char])

(’a’, True, 1) (Char, Bool, Int)

([1,2],sqrt) ([Int], Float->Float)

(1, (2, 3)) (Int, (Int, Int))


Но, сердце Haskell и всего функционального программирования — это, конечно, сами функции!


Функции



Функция, в современной математике, это закон соответствия, который сопоставляет каждому элементу x из данного множества A один единственный (или ни одного) элемент y из множества B.

Haskell, по своему назначению, это, прежде всего, язык математиков, поэтому синтаксис тут максимально точно соответствует этому определению.

Пример:

Square :: Integer -> Integer
Square x = x*x




Как вы, наверное, догадались, это функция возведения числа в квадрат. Разберем её подробно:

Первая строка — это объявление функции:

Имя_функции :: область_определения — > область _значений

Square :: Integer -> Integer

Тут следует сказать, что в Haskell совсем необязательно всегда определять функцию. В ряде случаев интерпретатор и так поймет какие у данной функции области определения и значения. Однако, опускать объявления — моветон.


Вторая строка — это определение функции:

Имя_функции параметры = правило_вычисления

Square x = x*x


Функция без параметров есть ничто иное, как константа:



e :: Float
e = exp 1.0


Функция с несколькими параметрами:



abcFormula :: Float -> Float -> Float -> [Float]
abcFormula a b c = [
(-b+sqrt(b*b-4.0*a*c))/(2.0*a),
(-b-sqrt(b*b-4.0*a*c))/(2.0*a)
]
-- находит корни уравнения ax^2+bx+c=0


Определения функций с альтернативами



Как и в любом языке, в Haskell есть конструкции ветвления.

Разберем их на примере функции abs (модуль).

If … then … else …

abs1 x = if x>=0 then x else -x


Case … of …



abs2 x = case x>=0 of
True -> x
False -> -x


Но, помимо стандартных if и case, в Haskell есть очень красивая и наиболее используемая конструкция ветвления. Так называемые, охранные выражения. Пример:



abs3 x | x>0 = x
| x<0 = -x
| otherwise = 0





Прямую черту следует читать, как: «при».

Читаем: «Функция abs3, с входным параметром x, при x>0 принимает значение x, при x

Конечно, мы могли записать все с помощью двух охранных выражений, но я записал три, что бы было понятно, что их может быть сколько угодно.

Otherwise в прелюдии определен очень просто:

otherwise :: Bool
otherwise = True




То есть, можно спокойно написать вместо «otherwise» «True», но это, опять же, моветон.
Сопоставление с образцом



Один из наиболее распространенных и эффективных приемов в Haskell — это сопоставление с образцом. Вместо параметра мы можем подсунуть функции пример того, как должен выглядеть параметр. Если образец подошел функция выполняется, если нет — переходит к следующему образцу. Например, определение факториала через рекурсию с помощью образцов:

fact :: Integer -> Integer
fact 0 = 1
fact n = (n+1) * fact (n)




Тоже самое, но, с помощью охранных выражений:

fact :: Integer -> Integer
fact n | n==0 = 1
| n>0 = n*fact (n-1)




Есть очень распространенный образец для списка: (x:xs). X — обозначает первый элемент, XS — остальной список (кроме первого элемента). «:» — операция присоединения элемента к списку. Примеры из прелюдии:

head :: [a] -> a
head (x:_) = x
head [] = error "Prelude.head: empty list"

tail :: [a] -> [a]
tail (_:xs) = xs
tail [] = error "Prelude.tail: empty list"




Функция head принимает на вход список чего угодно [a] и возвращает первый элемент этого списка. Функция tail принимает на вход список чего угодно [a] и изымает из этого списка первый элемент.

«_» — означает, что данный элемент нас не интересует.

Ну вот, на сегодня и все. Если будет интерес, в ближайшее время напишу продолжение.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers.


Комментариев нет:

Отправить комментарий