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

в 17:48, , рубрики: haskell, функциональное программирование, метки: ,

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<0 принимает значение -x, и в любом другом случае принимает значение 0».
Конечно, мы могли записать все с помощью двух охранных выражений, но я записал три, что бы было понятно, что их может быть сколько угодно.
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] и изымает из этого списка первый элемент.
«_» — означает, что элемент находящийся тут нас не интересует.

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

Автор: serr

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js