- Haskell: навстречу функциональному программированию
- Что такое Haskell?
- Настройка среды Haskell
- Начало работы с Haskell
- Пример программы
- Основные операции
- Символы
- Строки
- Логические типы данных
- Списки
- Метод Length
- Метод Reverse
- Метод Add
- Метод Delete
- Кортеж
- Первый элемент
- Методы Head and tail
- Условные инструкции
- Инструкция if-else
- Функции
- Сопоставление с образцом
- Охранные выражения
- Рекурсия
- Лямбда-выражения
- Модули
- Пользовательские модули
- Полезные ресурсы:
- Заключение
- Конспекты лекций «Haskell как первый язык программирования». Часть1
Haskell: навстречу функциональному программированию
Haskell — это функциональный язык программирования, разработанный специально для обработки символьных вычислений и списков.
Данная статья носит обучающий характер и предназначена для новичков, стремящихся понять основные положения Haskell.
Что такое Haskell?
Haskell — широко распространенный чистый функциональный язык.
Функциональные программы больше подходят для использования в многопоточной среде и предусматривают параллельное выполнение, добиваясь более точной и эффективной производительности. В традиционных языках программирования мы инструктируем компилятор, как выполнить то или иное действие.
Но в Haskell действует иной принцип — здесь мы говорим, что делать. Кроме того, это ленивый язык, поэтому программа не выполняет код, если считает его необязательным.
Программа на Haskell — это не что иное, как ряд выполняющихся функций.
Haskell — строго типизированный язык. Это значит, что компилятор достаточно сообразителен, чтобы определить тип объявленной переменной. Следовательно, у нас нет необходимости явно указывать ее тип.
Настройка среды Haskell
Для настройки среды Haskell на компьютере Windows перейдите по этой ссылке на официальный веб-сайт и загрузите соответствующий установочный пакет.
Если же необходимо настроить эту среду в системе MAC, воспользуйтесь следующей ссылкой для перехода на официальный сайт и загрузите установщик Mac.
Процесс настройки в Linux выглядит следующим образом:
$ sudo apt-get install haskell-platform
Начало работы с Haskell
Вы без особого труда начнете программировать на Haskell — достаточно лишь ввести следующую команду в терминал:
$ ghci GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim . linking . done. Loading package integer-gmp . linking . done. Loading package base . linking . done. Prelude>
Вот теперь можно писать код.
Пример программы
Это простой пример, демонстрирующий динамизм Haskell. Рассмотрим следующий код:
Prelude> main = putStrLn «Hello Medium»
Основные операции
Haskell — настолько смышленый язык, что распознает число как число. Поэтому вам не нужно извне указывать его тип, как это обычно принято в других языках программирования.
Символы
Наряду с числами, Haskell способен распознавать символы, поступающие в него при вводе данных.
Для отображения типа переменной можно ввести следующую строку кода
и получить вот такой результат:
Строки
Строка — это не что иное, как набор символов. Создадим следующую строку
Если нужно узнать тип этой строки, снова воспользуйтесь :t :
Как уже ранее упоминалось, строка — это просто набор символов, поэтому она вернется в качестве типа данных Char .
Логические типы данных
С логическими типами всё также просто и понятно, как и с другими данными. Следующий пример демонстрирует некоторые из них.
Списки
Подобно другим типам данных в Haskell, List также обладает не меньшей практической значимостью. Как следует из примера, [a,b,c] представляет собой список символов. Следовательно, List — это набор элементов одного и того же типа данных, разделенных запятыми. Создадим свой список:
Метод Length
Списки имеют несколько методов. Допустим, у вас есть список x, длину которого необходимо определить. Следующий метод как раз для вас:
Метод Reverse
Этот метод используется для обращения порядка следования элементов списка:
Метод Add
Для добавления элемента в список можно использовать оператор ++ :
Этот код объединяет два списка: x и y.
Метод Delete
Используйте drop для удаления одного элемента из списка:
Кортеж
Haskell предоставляет еще один способ объявления нескольких значений в одном типе данных. Речь идет о кортеже, который можно рассматривать как список. Однако между ними есть ряд технических отличий.
Кортеж содержит фиксированное число элементов. Он относится к неизменяемым типам. Создается кортеж следующим образом:
Это кортеж содержит три элемента: два числа и символ.
Как и в случае со списками, у кортежей есть методы, например, для определения в нем первого или последнего элемента.
Первый элемент
Для извлечения первого элемента кортежа используется следующий метод:
Методы Head and tail
Метод head также предназначен для извлечения первого элемента кортежа:
Метод tail позволит вам извлечь не только последний или второй элемент кортежа, но и все его элементы за исключением первого:
Условные инструкции
Условные инструкции — это программная возможность, позволяющая применять условие в процессе работы кода. Программист может выполнить набор инструкций в зависимости от предварительно заданного условия.
Haskell располагает такими условными инструкциями, как:
Инструкция if-else
Синтаксис выражений if выглядит следующим образом:
Функции
Функции играют важную роль в Haskell, поскольку он является языком функционального программирования. Подобно другим языкам, в нем существует определение и объявление функций.
Следующий небольшой пример с функцией add поможет нам подробно разобраться в сути этой концепции.
add :: Integer -> Integer -> Integer --function declaration
add x y = x + y --function definition
main = do
putStrLn "The addition of the two numbers is:"
print(add 2 5) --calling a function
The addition of the two numbers is:
7
Сопоставление с образцом
Этот метод предполагает сопоставление с конкретным типом выражения и позволяет упростить код.
Рассмотрим следующий блок кода:
fact :: Int -> Int fact 0 = 1 fact n = n * fact ( n - 1 ) main = do putStrLn "The factorial of 4 is:" print (fact 4)
В данном примере метод сопоставления с образцом использовался для вычисления факториала числа.
Охранные выражения
Принцип охранных выражений очень похож на сопоставление с образцом, но вот используются они для тестирования свойств выражений. В следующем примере кода в программу факториала были внесены изменения с учетом концепции охранных выражений:
fact :: Integer -> Integer fact n | n == 0 = 1 | n /= 0 = n * fact (n-1) main = do putStrLn "The factorial of 4 is:" print (fact 4)
Рекурсия
Рекурсия — это ситуация, при которой функция вызывает саму себя. Haskell не предоставляет возможность повторять цикл выражения более одного раза.
Он предлагает вам разбить всю функциональность на несколько разных функций и реализовать ее, используя рекурсию.
В данном примере для вычисления факториала 4 использовались оба метода: сопоставление с образцом и рекурсия.
fact :: Int -> Int fact 0 = 1 fact n = n * fact ( n - 1 ) main = do putStrLn "The factorial of 4 is:" print (fact 4)
Лямбда-выражения
Функция, не имеющая определения, получила название лямбда-функции. Она обозначается символом \ .
main = do putStrLn "The successor of 5 is:" print ((\x -> x + 1) 5)
Модули
Если у вас был опыт программирования на Java, то вы в курсе, что все классы объединяются в папки, так называемые пакеты. Подобно этому и Haskell можно рассматривать как набор модулей.
Например, предлагаю вашему вниманию модуль list:
И сразу функциональности List попадают в ваше распоряжение.
Среди других модулей можно выделить следующие:
Пользовательские модули
Создадим модуль Custom и определим в нем несколько функций.
module Custom ( showEven, showBoolean ) where showEven:: Int-> Bool showEven x = do if x 'rem' 2 == 0 then True else False showBoolean :: Bool->Int showBoolean c = do if c == True then 1 else 0
А теперь импортируем его программу, выполнив следующее действие:
import Custom main = do print(showEven 4) print(showBoolean True)
Полезные ресурсы:
Заключение
Надеюсь, что материал данной статьи помог вам составить общее представление о Haskell, и теперь вы без особого труда сможете написать на нем простой код.
Полагаю, что овладение Haskell упростит вам изучение других функциональных языков программирования.
Конспекты лекций «Haskell как первый язык программирования». Часть1
Привет 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
Функция без параметров есть ничто иное, как константа:
Функция с несколькими параметрами:
Спасибо janatem за разъяснения (читай комментарии).
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
abs2 x = case x>=0 of True -> x False -> -x
Но, помимо стандартных if и case, в Haskell есть очень красивая и наиболее используемая конструкция ветвления. Так называемые, охранные выражения. Пример:
Прямую черту следует читать, как: «при».
Читаем: «Функция abs3, с входным параметром x, при x>0 принимает значение x, при x Конечно, мы могли записать все с помощью двух охранных выражений, но я записал три, что бы было понятно, что их может быть сколько угодно.
Otherwise в прелюдии определен очень просто:
otherwise :: Bool otherwise = True
То есть, можно спокойно написать вместо «otherwise» «True», но это, опять же, моветон.
Сопоставление с образцом
Один из наиболее распространенных и эффективных приемов в Haskell — это сопоставление с образцом. Вместо параметра мы можем подсунуть функции пример того, как должен выглядеть параметр. Если образец подошел функция выполняется, если нет — переходит к следующему образцу. Например, определение факториала через рекурсию с помощью образцов:
fact :: Integer -> Integer fact 0 = 1 fact n = n * fact (n-1)
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] и изымает из этого списка первый элемент.
«_» — означает, что данный элемент нас не интересует.
Ну вот, на сегодня и все. Если будет интерес, в ближайшее время напишу продолжение.