Миран Липовача - Изучай Haskell во имя добра!
- Название:Изучай Haskell во имя добра!
- Автор:
- Жанр:
- Издательство:ДМК Пресс
- Год:2012
- Город:Москва
- ISBN:978-5-94074-749-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Миран Липовача - Изучай Haskell во имя добра! краткое содержание
Язык Haskell имеет множество впечатляющих возможностей, но главное его свойство в том, что меняется не только способ написания кода, но и сам способ размышления о проблемах и возможных решениях. Этим Haskell действительно отличается от большинства языков программирования. С его помощью мир можно представить и описать нестандартным образом. И поскольку Haskell предлагает совершенно новые способы размышления о проблемах, изучение этого языка может изменить и стиль программирования на всех прочих.
Ещё одно необычное свойство Haskell состоит в том, что в этом языке придаётся особое значение рассуждениям о типах данных. Как следствие, вы помещаете больше внимания и меньше кода в ваши программы.
Вне зависимости от того, в каком направлении вы намерены двигаться, путешествуя в мире программирования, небольшой заход в страну Haskell себя оправдает. А если вы решите там остаться, то наверняка найдёте чем заняться и чему поучиться!
Эта книга поможет многим читателям найти свой путь к Haskell.
Отображения, монады, моноиды и другое! Всё сказано в названии: «Изучай Хаскель во имя добра!» – весёлый иллюстрированный самоучитель по этому сложному функциональному языку.
С помощью оригинальных рисунков автора, отсылке к поп-культуре, и, самое главное, благодаря полезным примерам кода, эта книга обучает основам функционального программирования так, как вы никогда не смогли бы себе представить.
Вы начнете изучение с простого материала: основы синтаксиса, рекурсия, типы и классы типов. Затем, когда вы преуспеете в основах, начнется настоящий мастер-класс от профессионала: вы изучите, как использовать аппликативные функторы, монады, застежки, и другие легендарные конструкции Хаскеля, о которых вы читали только в сказках.
Продираясь сквозь образные (и порой безумные) примеры автора, вы научитесь:
• Смеяться в лицо побочным эффектам, поскольку вы овладеете техниками чистого функционального программирования.
• Использовать волшебство «ленивости» Хаскеля для игры с бесконечными наборами данных.
• Организовывать свои программы, создавая собственные типы, классы типов и модули.
• Использовать элегантную систему ввода-вывода Хаскеля, чтобы делиться гениальностью ваших программ с окружающим миром.
Нет лучшего способа изучить этот мощный язык, чем чтение «Изучай Хаскель во имя добра!», кроме, разве что, поедания мозга его создателей. Миран Липовача (Miran Lipovača) изучает информатику в Любляне (Словения). Помимо его любви к Хаскелю, ему нравится заниматься боксом, играть на бас-гитаре и, конечно же, рисовать. У него есть увлечение танцующими скелетами и числом 71, а когда он проходит через автоматические двери, он притворяется, что на самом деле открывает их силой своей мысли.
Изучай Haskell во имя добра! - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Выражение fmap (*2)
– это функция, которая получает функтор f
над числами и возвращает функтор над числами. Таким функтором могут быть список, значение Maybe
, Either String
или что-то другое. Выражение fmap (replicate 3)
получит функтор над любым типом и вернёт функтор над списком элементов данного типа. Это становится ещё очевиднее, если мы частично применим, скажем, fmap
(++"!")
, а затем привяжем её к имени в GHCi.
Вы можете рассматривать fmap
двояко:
• как функцию, которая принимает функцию и значение функтора, а затем отображает это значение функтора с помощью данной функции;
• как функцию, которая принимает функцию и втягивает её в функтор, так чтобы она оперировала значениями функторов.
Обе точки зрения верны.
Тип fmap (replicate 3) :: (Functor f) => f a –> f [a]
означает, что функция будет работать с любым функтором. Что именно она будет делать, зависит от функтора. Если мы применим fmap
(replicate 3)
к списку, будет выбрана реализация fmap
для списка, то есть просто map
. Если мы применим её к Maybe a
, она применит replicate 3
к значению внутри Just
. Если это значение равно Nothing
, то оно останется равным Nothing
. Вот несколько примеров:
ghci> fmap (replicate 3) [1,2,3,4]
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]]
ghci> fmap (replicate 3) (Just 4)
Just [4,4,4]
ghci> fmap (replicate 3) (Right "ля")
Right ["ля","ля","ля"]
ghci> fmap (replicate 3) Nothing
Nothing
ghci> fmap (replicate 3) (Left "фуу")
Left "фуу"
Законы функторов

Предполагается, что все функторы проявляют определённые свойства и поведение. Они должны надёжно вести себя как сущности, которые можно отобразить. Применение функции fmap
к функтору должно только отобразить функтор с помощью функции – ничего более. Это поведение описано в законах функторов. Все экземпляры класса Functor
должны следовать этим двум законам. Язык Haskell не принуждает, чтобы эти законы выполнялись автоматически, поэтому вы должны проверять их сами, когда создаёте функтор. Все экземпляры класса Functor
в стандартной библиотеке выполняют эти законы.
Закон 1
Первый закон функторов гласит, что если мы применяем функцию id
к значению функтора, то значение функтора, которое мы получим, должно быть таким же, как первоначальное значение функтора. В формализованной записи это выглядит так: fmap id = id
. Иными словами, если мы применим fmap id
к значению функтора, это должно быть то же самое, что и просто применение функции id
к значению. Вспомните, что id
– это функция тождества, которая просто возвращает свой параметр неизменным. Она также может быть записана в виде \x –> x
. Если воспринимать значение функтора как нечто, что может быть отображено, то закон fmap id = id
представляется довольно очевидным.
Давайте посмотрим, выполняется ли он для некоторых значений функторов:
ghci> fmap id (Just 3)
Just 3
ghci> id (Just 3)
Just 3
ghci> fmap id [1..5]
[1,2,3,4,5]
ghci> id [1..5]
[1,2,3,4,5]
ghci> fmap id []
[]
ghci> fmap id Nothing
Nothing
Если посмотреть на реализацию функцию fmap
, например, для типа Maybe
, мы можем понять, почему выполняется первый закон функторов:
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing= Nothing
Мы представляем, что функция id
играет роль параметра f
в этой реализации. Нам видно, что если мы применяем fmap id
к значению Just x
, то результатом будет Just (id x)
, и поскольку id
просто возвращает свой параметр, мы можем сделать вывод, что Just (id x)
равно Just x
. Теперь нам известно, что если мы применим функцию id
к значению типа Maybe
, созданному с помощью конструктора данных Just
, обратно мы получим то же самое значение.
Видно, что применение функции id
к значению Nothing
возвращает то же самое значение Nothing
. Поэтому из этих двух равенств в реализации функции fmap
нам видно, что закон fmap id = id
соблюдается.
Закон 2
Второй закон гласит, что композиция двух функций и последующее применение результирующей функции к функтору должны давать тот же результат, что и применение первой функции к функтору, а затем применение другой. В формальной записи это выглядит так: fmap (f . g) = fmap f . fmap g
. Или если записать по-другому, то для любого значения функтора x
должно выполняться следующее: fmap
(f
.
g)
x
=
fmap
f
(fmap
g
x)
.
Если мы выявили, что некоторый тип подчиняется двум законам функторов, надо надеяться, что он обладает такими же фундаментальными поведениями, как и другие функторы, когда дело доходит до отображения. Мы можем быть уверены, что когда мы применяем к нему функцию fmap
, за кулисами ничего не произойдёт, кроме отображения, и он будет действовать как сущность, которая может быть отображена – то есть функтор.
Можно выяснить, как второй закон выполняется по отношению к некоторому типу, посмотрев на реализацию функции fmap
для этого типа, а затем использовав метод, который мы применяли, чтобы проверить, подчиняется ли тип Maybe
первому закону. Итак, чтобы проверить, как второй закон функторов выполняется для типа Maybe
, если мы применим выражение fmap
(f . g)
к значению Nothing
, мы получаем то же самое значение Nothing
, потому что применение любой функции к Nothing
даёт Nothing
. Если мы выполним выражение fmap f (fmap g Nothing)
, то получим результат Nothing
по тем же причинам.
Довольно просто увидеть, как второй закон выполняется для типа Maybe
, когда значение равно Nothing
. Но что если это значение Just
? Ладно – если мы выполним fmap (f . g) (Just x)
, из реализации нам будет видно, что это реализовано как Just ((f . g) x)
; аналогичной записью было бы Just (f (g x))
. Если же мы выполним fmap f (fmap g (Just x))
, то из реализации увидим, что fmap g (Just x)
– это Just (g x)
. Следовательно, fmap f (fmap g (Just x))
равно fmap f (Just (g x))
, а из реализации нам видно, что это равнозначно Just (f (g x))
.
Если вы немного смущены этим доказательством, не волнуйтесь. Убедитесь, что вы понимаете, как устроена композиция функций. Часто вы можете интуитивно понимать, как выполняются эти законы, поскольку типы действуют как контейнеры или функции. Вы также можете просто проверить их на нескольких разных значениях типа – и сумеете с определённой долей уверенности сказать, что тип действительно подчиняется этим законам.
Читать дальшеИнтервал:
Закладка: