Я читал книгу «Learn You a Haskell» до того момента, когда они представляют монады и все такое, как Just a. Это настолько нелогично для меня, что мне просто хочется бросить учиться.
Но я очень хочу попробовать.
Мне интересно, смогу ли я хотя бы на некоторое время отказаться от продвинутых концепций и просто начать использовать другие части языка для выполнения множества практических задач с более основными частями Haskell, то есть функциями, стандартным вводом-выводом, обработкой файлов, интерфейс базы данных и тому подобное.
Это разумный подход к изучению, как использовать Haskell?
Ответы:
Давайте сначала проведем различие между изучением абстрактных понятий и изучением конкретных примеров из них.
Вы не будете слишком далеко игнорировать все конкретные примеры по той простой причине, что они совершенно вездесущи. Фактически, абстракции существуют в значительной степени потому, что они объединяют то, что вы будете делать в любом случае с конкретными примерами.
С другой стороны, сами абстракции, безусловно, полезны , но в них нет необходимости. Вы можете довольно далеко проигнорировать абстракции полностью и просто использовать различные типы напрямую. Вы захотите понять их в конце концов, но вы всегда можете вернуться к этому позже. На самом деле, я почти гарантирую, что если вы сделаете это, когда вернетесь к этому, вы будете бить себя по лбу и удивляться, почему вы потратили все это время на трудный путь, вместо того, чтобы использовать удобные инструменты общего назначения.
Взять хотя
Maybe a
бы пример. Это просто тип данных:Это все, кроме самодокументирования; это необязательное значение. Либо у вас «просто» что-то типа
a
, либо у вас ничего нет. Допустим, у вас есть какая-то функция поиска, которая возвращаетMaybe String
представление для поискаString
значения, которое может отсутствовать. Таким образом, вы сопоставляете шаблон со значением, чтобы увидеть, какое оно:Это все!
На самом деле, вам больше ничего не нужно. Нет
Functor
s илиMonad
s или что-нибудь еще. Они выражают общие способы использованияMaybe a
ценностей ... но это просто идиомы, "шаблоны проектирования", как бы вы это ни называли.Единственное место, где вы действительно не можете избежать этого
IO
, - это таинственный черный ящик, так что не стоит пытаться понять, что это значит как-тоMonad
или что-то еще.На самом деле, вот шпаргалка для всего, что вам действительно нужно знать
IO
на данный момент:Если у чего-то есть тип
IO a
, это означает, что это процедура , которая что-то делает и выплевываетa
значение.Когда у вас есть блок кода с использованием
do
нотации, напишите что-то вроде этого:... означает выполнить процедуру справа от
<-
и назначить результат имени слева.Тогда как если у вас есть что-то вроде этого:
... это означает присвоение значения простого выражения (не процедуры) справа от
=
имени имени слева.Если вы поместите что-то туда без присвоения значения, вот так:
... это означает выполнение процедуры и игнорирование всего, что она возвращает. Некоторые процедуры имеют тип
IO ()
-()
тип является своего рода заполнителем, который ничего не говорит, так что это просто означает, что процедура что-то делает и не возвращает значение. Вроде какvoid
функция в других языках.Выполнение одной и той же процедуры более одного раза может дать разные результаты; это своего рода идея. Вот почему нет способа «удалить» значение
IO
из значения, потому что что-тоIO
не является значением, это процедура для получения значения.Последняя строка в
do
блоке должна быть простой процедурой без присваивания, где возвращаемое значение этой процедуры становится возвращаемым значением для всего блока. Если вы хотите, чтобы возвращаемое значение использовало какое-то уже присвоенное значение,return
функция принимает простое значение и дает вам неоперативную процедуру, которая возвращает это значение.В этом нет ничего особенного
IO
; эти процедуры на самом деле представляют собой простые значения, и вы можете передавать их и комбинировать по-разному. Только когда они выполняются вdo
блоке, вызванном где-тоmain
, они делают что-либо.Итак, в чем-то вроде этого совершенно скучного, стереотипного примера программы:
... вы можете прочитать его, как императивную программу. Мы определяем процедуру с именем
hello
. При выполнении сначала выполняется процедура для печати сообщения с вашим именем; затем он выполняет процедуру, которая читает строку ввода и присваивает результатname
; затем он присваивает выражение имениmsg
; тогда это печатает сообщение; затем он возвращает имя пользователя как результат всего блока. Посколькуname
это aString
, это означает, чтоhello
это процедура, которая возвращает aString
, поэтому она имеет типIO String
. И теперь вы можете выполнить эту процедуру в другом месте, так же, как она выполняетgetLine
.Пффф, монады. Кому они нужны?
источник
Они необходимы. Без них слишком просто использовать Haskell в качестве еще одного императивного языка, и хотя Саймон Пейтон Джонс однажды назвал Haskell, «лучший в мире язык императивного программирования», вы все равно упускаете лучшую часть.
Монады, преобразования монад, моноиды, функторы, аппликативные функторы, контравариантные функторы, стрелки, категории и т. Д. Являются шаблонами проектирования. Как только вы вписываете конкретную вещь, которую вы делаете, в одну из них, вы можете использовать огромное количество функций, написанных абстрактно. Эти классы не просто сбивают вас с толку, они делают вашу жизнь проще и продуктивнее. Они, на мой взгляд, являются основной причиной краткости хорошего кода на Haskell.
источник
Строго ли это необходимо, если вы просто хотите запустить что-то? Нет.
Нужно ли это, если вы хотите писать красивые идиоматические программы на Haskell? Абсолютно.
При программировании на Haskell полезно помнить две вещи:
Система типов поможет вам. Если вы составляете свою программу из очень полиморфного кода, насыщенного типами, очень часто вы можете попасть в удивительную ситуацию, когда тип функции, которую вы хотите, приведет вас к (единственной!) Правильной реализации .
Различные доступные библиотеки были разработаны с использованием принципа # 1.
Поэтому, когда я пишу программу на Haskell, я начинаю с написания типов. Затем я начинаю заново и записываю некоторые более общие типы (и, если они могут быть экземплярами существующих классов типов, тем лучше). Затем я пишу некоторые функции, которые дают мне значения типов, которые я хочу. (Затем я играю с ними
ghci
и, возможно, напишу несколько тестов quickCheck.) И, наконец, я склеиваю все это вместеmain
.Можно написать уродливый Haskell, который просто запускает что-то. Но есть еще много чего, когда вы достигнете этой стадии.
Удачи!
источник