Миран Липовача - Изучай Haskell во имя добра!
- Название:Изучай Haskell во имя добра!
- Автор:
- Жанр:
- Издательство:ДМК Пресс
- Год:2012
- Город:Москва
- ISBN:978-5-94074-749-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Миран Липовача - Изучай Haskell во имя добра! краткое содержание
Язык Haskell имеет множество впечатляющих возможностей, но главное его свойство в том, что меняется не только способ написания кода, но и сам способ размышления о проблемах и возможных решениях. Этим Haskell действительно отличается от большинства языков программирования. С его помощью мир можно представить и описать нестандартным образом. И поскольку Haskell предлагает совершенно новые способы размышления о проблемах, изучение этого языка может изменить и стиль программирования на всех прочих.
Ещё одно необычное свойство Haskell состоит в том, что в этом языке придаётся особое значение рассуждениям о типах данных. Как следствие, вы помещаете больше внимания и меньше кода в ваши программы.
Вне зависимости от того, в каком направлении вы намерены двигаться, путешествуя в мире программирования, небольшой заход в страну Haskell себя оправдает. А если вы решите там остаться, то наверняка найдёте чем заняться и чему поучиться!
Эта книга поможет многим читателям найти свой путь к Haskell.
Отображения, монады, моноиды и другое! Всё сказано в названии: «Изучай Хаскель во имя добра!» – весёлый иллюстрированный самоучитель по этому сложному функциональному языку.
С помощью оригинальных рисунков автора, отсылке к поп-культуре, и, самое главное, благодаря полезным примерам кода, эта книга обучает основам функционального программирования так, как вы никогда не смогли бы себе представить.
Вы начнете изучение с простого материала: основы синтаксиса, рекурсия, типы и классы типов. Затем, когда вы преуспеете в основах, начнется настоящий мастер-класс от профессионала: вы изучите, как использовать аппликативные функторы, монады, застежки, и другие легендарные конструкции Хаскеля, о которых вы читали только в сказках.
Продираясь сквозь образные (и порой безумные) примеры автора, вы научитесь:
• Смеяться в лицо побочным эффектам, поскольку вы овладеете техниками чистого функционального программирования.
• Использовать волшебство «ленивости» Хаскеля для игры с бесконечными наборами данных.
• Организовывать свои программы, создавая собственные типы, классы типов и модули.
• Использовать элегантную систему ввода-вывода Хаскеля, чтобы делиться гениальностью ваших программ с окружающим миром.
Нет лучшего способа изучить этот мощный язык, чем чтение «Изучай Хаскель во имя добра!», кроме, разве что, поедания мозга его создателей. Миран Липовача (Miran Lipovača) изучает информатику в Любляне (Словения). Помимо его любви к Хаскелю, ему нравится заниматься боксом, играть на бас-гитаре и, конечно же, рисовать. У него есть увлечение танцующими скелетами и числом 71, а когда он проходит через автоматические двери, он притворяется, что на самом деле открывает их силой своей мысли.
Изучай Haskell во имя добра! - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Давайте напишем простую функцию, которая сообщает нам о нескольких первых элементах списка – в довольно неудобной, чересчур многословной форме.
tell :: (Show a) => [a] –> String
tell [] = "Список пуст"
tell (x:[]) = "В списке один элемент: " ++ show x
tell (x:y:[]) = "В списке два элемента: " ++ show x ++ " и " ++ show y
tell (x:y:_) = "Список длинный. Первые два элемента: " ++ show x
++ " и " ++ show y
Обратите внимание, что образцы (x:[])
и (x:y:[])
можно записать как [x]
и [x,y]
. Но мы не можем записать (x:y:_)
с помощью квадратных скобок, потому что такая запись соответствует любому списку длиной два или более.
Вот несколько примеров использования этой функции:
ghci> tell [1]
"В списке один элемент: 1"
ghci> tell [True, False]
"В списке два элемента: True и False"
ghci> tell [1, 2, 3, 4]
"Список длинный. Первые два элемента: 1 и 2"
ghci> tell []
"Список пуст"
Функцию tell
можно вызывать совершенно безопасно, потому что её параметр можно сопоставлять пустому списку, одноэлементному списку, списку с двумя и более элементами. Она умеет работать со списками любой длины и всегда знает, что нужно возвратить.
А что если определить функцию, которая умеет обрабатывать только списки с тремя элементами? Вот один такой пример:
badAdd :: (Num a) => [a] -> a
badAdd (x:y:z:[]) = x + y + z
А вот что случится, если подать ей не то, что она ждёт:
ghci> badAdd [100, 20]
*** Exception: Non-exhaustive patterns in function badAdd
Это не так уж и хорошо. Если подобное случится в скомпилированной программе, то она просто вылетит.
И последнее замечание относительно сопоставления с образцами для списков: в образцах нельзя использовать операцию ++
(напомню, что это объединение двух списков). К примеру, если вы попытаетесь написать в образце (xs++ys)
, то Haskell не сможет определить, что должно попасть в xs
, а что в ys
. Хотя и могут показаться логичными сопоставления типа (xs++[x,y,z])
или даже (xs ++ [x])
, работать это не будет – такова природа списков [7] На деле в образцах нельзя использовать операторы, представляющие собой двухместные функции (например, + , / и ++ ), поскольку при сопоставлении с образцами производится, по сути, обратная операция. Как сопоставить заданное число 5 с образцом (x + y) ? Это можно сделать несколькими способами, то есть ситуация неопределённа. Между тем оператор : является конструктором данных (все бинарные операторы, начинающиеся с символа : , могут использоваться как конструкторы данных), поэтому для него можно произвести однозначное сопоставление. — Прим. ред.
.
Именованные образцы
Ещё одна конструкция называется именованным образцом . Это удобный способ разбить что-либо в соответствии с образцом и связать результат разбиения с переменными, но в то же время сохранить ссылку на исходные данные. Такую задачу можно выполнить, поместив некий идентификатор образца и символ @
перед образцом, описывающим структуру данных. Например, так выглядит образец xs@(x:y:ys)
.
Подобный образец работает так же, как ( x:y:ys)
, но вы легко можете получить исходный список по имени xs
, вместо того чтобы раз за разом печатать x:y:ys
в теле функции. Приведу пример:
firstLetter :: String –> String
firstLetter "" = "Упс, пустая строка!"
firstLetter all@(x:xs) = "Первая буква строки " ++ all ++ " это " ++ [x]
Загрузим эту функцию и посмотрим, как она работает:
ghci> firstLetter "Дракула"
"Первая буква строки Дракула это Д"
Эй, стража!

В то время как образцы – это способ убедиться, что значение соответствует некоторой форме, и разобрать его на части, сторожевые условия (охрана, охранные выражения) – это способ проверить истинность некоторого свойства значения или нескольких значений, переданных функции. Тут можно провести аналогию с условным выражением if
: оно работает схожим образом. Однако охранные выражения гораздо легче читать, если у вас имеется несколько условий; к тому же они отлично работают с образцами.
Вместо того чтобы объяснять их синтаксис, давайте просто напишем функцию с использованием охранных условий. Эта простая функция будет оценивать вас на основе ИМТ (индекса массы тела). Ваш ИМТ равен вашему весу, разделённому на квадрат вашего роста.
Если ваш ИМТ меньше 18,5, можно считать вас тощим. Если ИМТ составляет от 18,5 до 25, ваш вес в пределах нормы. От 25 до 30 – вы полненький; более 30 – тучный. Запишем эту функцию (мы не будем рассчитывать ИМТ, функция принимает его как параметр и ругнёт вас соответственно).
bmiTell :: Double -> String
bmiTell bmi
| bmi <= 18.5 = "Слышь, эмо, ты дистрофик!"
| bmi <= 25.0 = "По части веса ты в норме. Зато, небось, уродец!"
| bmi <= 30.0 = "Ты толстый! Сбрось хоть немного веса!"
| otherwise = "Мои поздравления, ты жирный боров!"
Охранные выражения обозначаются вертикальными чёрточками после имени и параметров функции. Обычно они печатаются с отступом вправо и начинаются с одной позиции. Охранное выражение должно иметь тип Bool
. Если после вычисления условие имеет значение True
, используется соответствующее тело функции. Если вычисленное условие ложно, проверка продолжается со следующего условия, и т. д.
Если мы вызовем эту функцию с параметром 24.3
, она вначале проверит, не является ли это значение меньшим или равным 18.5
. Так как охранное выражение на данном значении равно False
, функция перейдёт к следующему варианту. Проверяется следующее условие, и так как 24.3
меньше, чем 25.0
, будет возвращена вторая строка.
Это очень напоминает большие деревья условий if
– else
в императивных языках программирования – только такой способ записи значительно лучше и легче для чтения. Несмотря на то что большие деревья условий if
– else
обычно не рекомендуется использовать, иногда задача представлена в настолько разрозненном виде, что просто невозможно обойтись без них. Охранные выражения – прекрасная альтернатива для таких задач.
Во многих случаях последним охранным выражением является otherwise
(«иначе»). Значение otherwise
определяется просто: otherwise = True
; такое условие всегда истинно. Работа условий очень похожа на то, как работают образцы, но образцы проверяют входные данные, а охранные выражения могут производить любые проверки.
Если все охранные выражения ложны (и при этом мы не записали otherwise
как последнее условие), вычисление продолжается со следующей строки определения функции. Вот почему сопоставление с образцом и охранные выражения так хорошо работают вместе. Если нет ни подходящих условий, ни клозов, будет сгенерирована ошибка времени исполнения.
Интервал:
Закладка: