Миран Липовача - Изучай Haskell во имя добра!
- Название:Изучай Haskell во имя добра!
- Автор:
- Жанр:
- Издательство:ДМК Пресс
- Год:2012
- Город:Москва
- ISBN:978-5-94074-749-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Миран Липовача - Изучай Haskell во имя добра! краткое содержание
Язык Haskell имеет множество впечатляющих возможностей, но главное его свойство в том, что меняется не только способ написания кода, но и сам способ размышления о проблемах и возможных решениях. Этим Haskell действительно отличается от большинства языков программирования. С его помощью мир можно представить и описать нестандартным образом. И поскольку Haskell предлагает совершенно новые способы размышления о проблемах, изучение этого языка может изменить и стиль программирования на всех прочих.
Ещё одно необычное свойство Haskell состоит в том, что в этом языке придаётся особое значение рассуждениям о типах данных. Как следствие, вы помещаете больше внимания и меньше кода в ваши программы.
Вне зависимости от того, в каком направлении вы намерены двигаться, путешествуя в мире программирования, небольшой заход в страну Haskell себя оправдает. А если вы решите там остаться, то наверняка найдёте чем заняться и чему поучиться!
Эта книга поможет многим читателям найти свой путь к Haskell.
Отображения, монады, моноиды и другое! Всё сказано в названии: «Изучай Хаскель во имя добра!» – весёлый иллюстрированный самоучитель по этому сложному функциональному языку.
С помощью оригинальных рисунков автора, отсылке к поп-культуре, и, самое главное, благодаря полезным примерам кода, эта книга обучает основам функционального программирования так, как вы никогда не смогли бы себе представить.
Вы начнете изучение с простого материала: основы синтаксиса, рекурсия, типы и классы типов. Затем, когда вы преуспеете в основах, начнется настоящий мастер-класс от профессионала: вы изучите, как использовать аппликативные функторы, монады, застежки, и другие легендарные конструкции Хаскеля, о которых вы читали только в сказках.
Продираясь сквозь образные (и порой безумные) примеры автора, вы научитесь:
• Смеяться в лицо побочным эффектам, поскольку вы овладеете техниками чистого функционального программирования.
• Использовать волшебство «ленивости» Хаскеля для игры с бесконечными наборами данных.
• Организовывать свои программы, создавая собственные типы, классы типов и модули.
• Использовать элегантную систему ввода-вывода Хаскеля, чтобы делиться гениальностью ваших программ с окружающим миром.
Нет лучшего способа изучить этот мощный язык, чем чтение «Изучай Хаскель во имя добра!», кроме, разве что, поедания мозга его создателей. Миран Липовача (Miran Lipovača) изучает информатику в Любляне (Словения). Помимо его любви к Хаскелю, ему нравится заниматься боксом, играть на бас-гитаре и, конечно же, рисовать. У него есть увлечение танцующими скелетами и числом 71, а когда он проходит через автоматические двери, он притворяется, что на самом деле открывает их силой своей мысли.
Изучай Haskell во имя добра! - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
main = do
putStrLn "Привет, как тебя зовут?"
name <���– getLine
putStrLn ("Привет, " ++ name ++ ", ну ты и хипстота!")
О, новый синтаксис!.. И он похож на синтаксис императивных языков. Если откомпилировать и запустить эту программу, она будет работать так, как вы и предполагаете. Обратите внимание: мы записали ключевое слово do
и затем последовательность шагов, как сделали бы в императивном языке. Каждый из этих шагов – действие ввода-вывода. Расположив их рядом с помощью ключевого слова do
, мы свели их в одно действие ввода-вывода. Получившееся действие имеет тип IO()
; это тип последнего оператора в цепочке.
По этой причине функция main
всегда имеет тип main :: IO < нечто >
, где < нечто >
– некоторый конкретный тип. По общепринятому соглашению обычно не пишут декларацию типа для функции main
.
В третьей строке можно видеть ещё один не встречавшийся нам ранее элемент синтаксиса, name
<���–
getLine
. Создаётся впечатление, будто считанная со стандартного входа строка сохраняется в переменной с именем name
. Так ли это на самом деле? Давайте посмотрим на тип getLine
.
ghci> :t getLine
getLine :: IO String
Ага!.. Функция getLine
– действие ввода-вывода, которое содержит результирующий тип – строку. Это понятно: действие ждёт, пока пользователь не введёт что-нибудь с терминала, и затем это нечто будет представлено как строка. Что тогда делает выражение name <���– getLine
? Можно прочитать его так: «выполнить действие getLine
и затем связать результат выполнения с именем name
». Функция getLine
имеет тип IO String
, поэтому образец name
будет иметь тип String
. Можно представить действие ввода-вывода в виде ящика с ножками, который ходит в реальный мир, что-то в нём делает (рисует граффити на стене, например) и иногда приносит обратно какие-либо данные. Если ящик что-либо принёс, единственный способ открыть его и извлечь данные – использовать конструкцию с символом <���–. Получить данные из действия ввода-вывода можно только внутри другого действия ввода-вывода. Таким образом, язык Haskell чётко разделяет чистую и «грязную» части кода. Функция getLine
– не чистая функция, потому что её результат может быть неодинаковым при последовательных вызовах. Вот почему она как бы «запачкана» конструктором типов IO
, и мы можем получить данные только внутри действий ввода-вывода, имеющих в сигнатуре типа маркёр IO
. Так как код для ввода-вывода также «испачкан», любое вычисление, зависящее от «испачканных» IO
-данных, также будет давать «грязный»результат.

Если я говорю «испачканы», это не значит, что мы не сможем использовать результат, содержащийся в типе IO
в чистом коде. Мы временно «очищаем» данные внутри действия, когда связываем их с именем. В выражении name <���– getLine
образец name
содержит обычную строку, представляющую содержимое ящика.
Мы можем написать сложную функцию, которая, скажем, принимает ваше имя как параметр (обычная строка) и предсказывает вашу удачливость или будущее всей вашей жизни, основываясь на имени:
main = do
putStrLn "Привет, как тебя зовут?"
name <���– getLine
putStrLn $ "Вот твоё будущее: " ++ tellFortune name
Функция tellFortune
(или любая другая, которой мы передаём значение name
) не должна знать ничего про IO
– это обычная функция String
–>
String
.
Посмотрите на этот образец кода. Корректен ли он?
nameTag = "Привет, меня зовут " ++ getLine
Если вы ответили «нет», возьмите с полки пирожок. Если ответили «да», убейте себя об стену… Шучу, не надо! Это выражение не сработает, потому что оператор ++
требует, чтобы оба параметра были списками одинакового типа. Левый параметр имеет тип String
(или [Char]
, если вам угодно), в то время как функция getLine
возвращает значение типа IO String
. Вы не сможете конкатенировать строку и результат действия ввода-вывода. Для начала нам нужно извлечь результат из действия ввода-вывода, чтобы получить значение типа String
, и единственный способ сделать это – выполнить что-то вроде name <���– getLine
внутри другого действия ввода-вывода. Если мы хотим работать с «нечистыми» данными, то должны делать это в «нечистом» окружении!… Итак, грязь от нечистоты распространяется как моровое поветрие, и в наших интересах делать часть для осуществления ввода-вывода настолько малой, насколько это возможно.
Каждое выполненное действие ввода-вывода заключает в себе результат. Вот почему наш предыдущий пример можно переписать так:
main = do
foo <- putStrLn "Привет, как тебя зовут?"
name <���– getLine
putStrLn ("Привет, " ++ name ++ ", ну ты и хипстота!")
Тем не менее образец foo
всегда будет получать значение ()
, так что большого смысла в этом нет. Заметьте: мы не связываем последний вызов функции putStrLn
с именем, потому что в блоке do
последний оператор, в отличие от предыдущих, не может быть связан с именем. Мы узнаем причины такого поведения немного позднее, когда познакомимся с миром монад. До тех пор можно считать, что блок do
автоматически получает результат последнего оператора и возвращает его в качестве собственного результата.
За исключением последней строчки, каждая строка в блоке do
может быть использована для связывания. Например, putStrLn "ЛЯ"
может быть записана как _ <���– putStrLn "ЛЯ"
. Но в этом нет никакого смысла, так что мы опускаем <���–
для действий ввода-вывода, не возвращающих значимого результата.
Иногда начинающие думают, что вызов
myLine = getLine
считает значение со стандартного входа и затем свяжет это значение с именем myLine
. На самом деле это не так. Такая запись даст функции getLine
другое синонимичное имя, в данном случае – myLine
. Запомните: чтобы получить значение из действия ввода-вывода, вы должны выполнять его внутри другого действия ввода-вывода и связывать его с именем при помощи символа <���–
.
Действие ввода-вывода будет выполнено, только если его имя main
или если оно помещено в составное действие с помощью блока do
. Также мы можем использовать блок do
для того, чтобы «склеить» несколько действий ввода-вывода в одно. Затем можно будет использовать его в другом блоке do
и т. д. В любом случае действие будет выполнено, только если оно каким-либо образом вызывается из функции main
.
Ах, да, есть ещё один способ выполнить действие ввода-вывода! Если напечатать его в интерпретаторе GHCi и нажать клавишу Enter, действие выполнится.
Читать дальшеИнтервал:
Закладка: