Миран Липовача - Изучай Haskell во имя добра!
- Название:Изучай Haskell во имя добра!
- Автор:
- Жанр:
- Издательство:ДМК Пресс
- Год:2012
- Город:Москва
- ISBN:978-5-94074-749-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Миран Липовача - Изучай Haskell во имя добра! краткое содержание
Язык Haskell имеет множество впечатляющих возможностей, но главное его свойство в том, что меняется не только способ написания кода, но и сам способ размышления о проблемах и возможных решениях. Этим Haskell действительно отличается от большинства языков программирования. С его помощью мир можно представить и описать нестандартным образом. И поскольку Haskell предлагает совершенно новые способы размышления о проблемах, изучение этого языка может изменить и стиль программирования на всех прочих.
Ещё одно необычное свойство Haskell состоит в том, что в этом языке придаётся особое значение рассуждениям о типах данных. Как следствие, вы помещаете больше внимания и меньше кода в ваши программы.
Вне зависимости от того, в каком направлении вы намерены двигаться, путешествуя в мире программирования, небольшой заход в страну Haskell себя оправдает. А если вы решите там остаться, то наверняка найдёте чем заняться и чему поучиться!
Эта книга поможет многим читателям найти свой путь к Haskell.
Отображения, монады, моноиды и другое! Всё сказано в названии: «Изучай Хаскель во имя добра!» – весёлый иллюстрированный самоучитель по этому сложному функциональному языку.
С помощью оригинальных рисунков автора, отсылке к поп-культуре, и, самое главное, благодаря полезным примерам кода, эта книга обучает основам функционального программирования так, как вы никогда не смогли бы себе представить.
Вы начнете изучение с простого материала: основы синтаксиса, рекурсия, типы и классы типов. Затем, когда вы преуспеете в основах, начнется настоящий мастер-класс от профессионала: вы изучите, как использовать аппликативные функторы, монады, застежки, и другие легендарные конструкции Хаскеля, о которых вы читали только в сказках.
Продираясь сквозь образные (и порой безумные) примеры автора, вы научитесь:
• Смеяться в лицо побочным эффектам, поскольку вы овладеете техниками чистого функционального программирования.
• Использовать волшебство «ленивости» Хаскеля для игры с бесконечными наборами данных.
• Организовывать свои программы, создавая собственные типы, классы типов и модули.
• Использовать элегантную систему ввода-вывода Хаскеля, чтобы делиться гениальностью ваших программ с окружающим миром.
Нет лучшего способа изучить этот мощный язык, чем чтение «Изучай Хаскель во имя добра!», кроме, разве что, поедания мозга его создателей. Миран Липовача (Miran Lipovača) изучает информатику в Любляне (Словения). Помимо его любви к Хаскелю, ему нравится заниматься боксом, играть на бас-гитаре и, конечно же, рисовать. У него есть увлечение танцующими скелетами и числом 71, а когда он проходит через автоматические двери, он притворяется, что на самом деле открывает их силой своей мысли.
Изучай Haskell во имя добра! - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
instance YesNo TrafficLight where
yesno Red = False
yesno _ = True
Ну что ж, мы определили несколько экземпляров, а теперь давайте поиграем с ними:
ghci> yesno $ length []
False
ghci> yesno "ха-ха"
True
ghci> yesno ""
False
ghci> yesno $ Just 0
True
ghci> yesno True
True
ghci> yesno EmptyTree
False
ghci> yesno []
False
ghci> yesno [0,0,0]
True
ghci> :t yesno
yesno :: (YesNo a) => a –> Bool
Та-ак, работает. Теперь сделаем функцию, которая работает, как оператор if
, но со значениями типов, для которых есть экземпляр класса YesNo
:
yesnoIf :: (YesNo y) => y –> a –> a –> a
yesnoIf yesnoVal yesResult noResult =
if yesno yesnoVal
then yesResult
else noResult
Всё довольно очевидно. Функция принимает значение для определения истинности и два других параметра. Если значение истинно, возвращается первый параметр; если нет – второй.
ghci> yesnoIf [] "ДА!" "НЕТ!"
"НЕТ!"
ghci> yesnoIf [2,3,4] "ДА!" "НЕТ!"
"ДА!"
ghci> yesnoIf True "ДА!" "НЕТ!"
"ДА!"
ghci> yesnoIf (Just 500) "ДА!" "НЕТ!"
"ДА!"
ghci> yesnoIf Nothing "ДА!" НЕТ!"
НЕТ!"
Класс типов Functor
Мы уже встречали множество классов типов из стандартной библиотеки. Ознакомились с классом Ord
, предусмотренным для сущностей, которые можно упорядочить. Вдоволь набаловались с классом Eq
, предназначенным для сравнения на равенство. Изучили класс Show
, предоставляющий интерфейс для типов, которые можно представить в виде строк. Наш добрый друг класс Read
помогает, когда нам надо преобразовать строку в значение некоторого типа. Ну а теперь приступим к рассмотрению класса типов Functor
, предназначенного для типов, которые могут быть отображены друг в друга.

Возможно, в этот момент вы подумали о списках: ведь отображение списков – это очень распространённая идиома в языке Haskell. И вы правы: списковый тип имеет экземпляр для класса Functor
.
Нет лучшего способа изучить класс типов Functor
, чем посмотреть, как он реализован. Вот и посмотрим:
fmap :: (a -> b) -> f a -> f b
Итак, что у нас имеется? Класс определяет одну функцию fmap
и не предоставляет для неё реализации по умолчанию. Тип функции fmap
весьма интересен. Во всех вышеприведённых определениях классов типов тип-параметр, игравший роль типа в классе, был некоторого конкретного типа, как переменная a
в сигнатуре (==) :: (Eq a) => a –> a –> Bool
. Но теперь тип-параметр f
не имеет конкретного типа (нет конкретного типа, который может принимать переменная, например Int
, Bool
или Maybe String
); в этом случае переменная – конструктор типов, принимающий один параметр. (Напомню: выражение Maybe Int
является конкретным типом, а идентификатор Maybe
– конструктор типов с одним параметром.) Мы видим, что функция fmap
принимает функцию из одного типа в другой и функтор, применённый к одному типу, и возвращает функтор, применённый к другому типу.
Если это звучит немного непонятно, не беспокойтесь. Всё прояснится, когда мы рассмотрим несколько примеров.
Гм-м… что-то мне напоминает объявление функции fmap
! Если вы не знаете сигнатуру функции map
, вот она:
map :: (a –> b) –> [a] –> [b]
О, как интересно! Функция map
берёт функцию из a
в b
и список элементов типа a
и возвращает список элементов типа b
. Друзья, мы только что обнаружили функтор! Фактически функция map
– это функция fmap
, которая работает только на списках. Вот как список сделан экземпляром класса Functor
:
instance Functor [] where
fmap = map
И всё! Заметьте, мы не пишем instance Functor [a] where
, потому что из определения функции
fmap :: (a –> b) –> f a –> f b
мы видим, что параметр f
должен быть конструктором типов, принимающим один тип. Выражение [a]
– это уже конкретный тип (список элементов типа a
), а вот []
– это конструктор типов, который принимает один тип; он может производить такие конкретные типы, как [Int]
, [String]
или даже [[String]]
.
Так как для списков функция fmap
– это просто map
, то мы получим одинаковые результаты при их использовании на списках:
map :: (a –> b) –> [a] –> [b]
ghci>fmap (*2) [1..3]
[2,4,6]
ghci> map (*2) [1..3]
[2,4,6]
Что случится, если применить функцию map
или fmap
к пустому списку? Мы получим опять же пустой список. Но функция fmap
преобразует пустой список типа [a]
в пустой список типа [b]
.
Экземпляр класса Functor для типа Maybe
Типы, которые могут вести себя как контейнеры по отношению к другим типам, могут быть функторами. Можно представить, что списки – это коробки с бесконечным числом отсеков; все они могут быть пустыми, или же один отсек заполнен, а остальные пустые, или несколько из них заполнены. А что ещё умеет быть контейнером для других типов? Например, тип Maybe
. Он может быть «пустой коробкой», и в этом случае имеет значение Nothing
, или же в нём хранится какое-то одно значение, например "ХА-ХА"
, и тогда он равен Just
"ХА-ХА"
.
Вот как тип Maybe
сделан функтором:
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
Ещё раз обратите внимание на то, как мы записали декларацию instance Functor Maybe where
вместо instance Functor (Maybe m) where
– подобно тому как мы делали для класса YesNo
. Функтор принимает конструктор типа с одним параметром, не конкретный тип. Если вы мысленно замените параметр f
на Maybe
, функция fmap
работает как (a –> b) –> Maybe a –> Maybe b
, только для типа Maybe
, что вполне себя оправдывает. Но если заменить f
на (Maybe m)
, то получится (a –> b) –> Maybe m a –> Maybe m b
, что не имеет никакого смысла, так как тип Maybe
принимает только один тип-параметр.
Как бы то ни было, реализация функции fmap
довольно проста. Если значение типа Maybe
– это Nothing
, возвращается Nothing
. Если мы отображаем «пустую коробку», мы получим «пустую коробку», что логично. Точно так же функция map
для пустого списка возвращает пустой список. Если это не пустое значение, а некоторое значение, упакованное в конструктор Just
, то мы применяем функцию к содержимому Just
:
ghci> fmap (++ " ПРИВЕТ, Я ВНУТРИ JUST") (Just "Серьёзная штука.")
Just "Серьёзная штука. ПРИВЕТ, Я ВНУТРИ JUST"
ghci> fmap (++ " ПРИВЕТ, Я ВНУТРИ JUST") Nothing
Интервал:
Закладка: