Насколько важны передовые концепции Haskell, такие как монады и аппликативные функторы, для большинства рутинных задач программирования?

16

Я читал книгу «Learn You a Haskell» до того момента, когда они представляют монады и все такое, как Just a. Это настолько нелогично для меня, что мне просто хочется бросить учиться.

Но я очень хочу попробовать.

Мне интересно, смогу ли я хотя бы на некоторое время отказаться от продвинутых концепций и просто начать использовать другие части языка для выполнения множества практических задач с более основными частями Haskell, то есть функциями, стандартным вводом-выводом, обработкой файлов, интерфейс базы данных и тому подобное.

Это разумный подход к изучению, как использовать Haskell?

Дан
источник
2
Я не знаю, как далеко вы доберетесь. Без монад вы не сможете сделать ничего полезного в Haskell, поскольку для выполнения чего-либо полезного в программировании (например, при написании серьезной программы, которую кто-то на самом деле хотел бы использовать) требуется ввод-вывод и состояние, которыми можно управлять только в Haskell. с помощью монад.
Мейсон Уилер
1
@dan - Я наконец понял монады Хаскелла, прочитав два документа: «Вы могли бы изобрести монады» и «Борьба с неуклюжим отрядом». Я не могу сказать, лучше ли они, чем "Learn You a Haskell", которую я не читал, но они работали на меня. Чтобы использовать нотацию do с монадой ввода-вывода, вы можете обойтись без особого понимания того, что такое монады - вы будете делать некоторые вещи, которые заставят экспертов смеяться или плакать, но, по крайней мере, внешне это мало чем отличается от использования обычный императивный язык. Но это стоит получить некоторые более глубокое понимание.
Steve314
2
@ Дэн, мне потребовалось почти десять лет, чтобы надоесть ООП и начать ценить / интересоваться функциональными языками. Я все еще изучал бы F # и Clojure, прежде чем дать серьезную попытку Haskell. В то время как личные проблемы хороши, есть кое-что, что можно сказать о вашем чувстве кишки и пути наименьшего сопротивления. Многое зависит от того, кто вы есть. Если вы сильно математический тип, то вам, вероятно, понравится Haskell / Schem с самого начала. Если вы больше любите делать это, это тоже нормально. Не подходите к Хаскеллу с отношением «делай или умри». Продолжайте изучать другие вещи, и когда вам скучно, возвращайтесь.
Работа
Спасибо за совет @Job. Я немного попробовал Clojure, но синтаксис Lisp действительно не работает для меня, как для чтения, так и для набора текста. Я нахожу синтаксис Хаскелла более естественным. Тем временем я рад использовать Ruby для проектов, но я надеюсь начать делать некоторые практические проекты на Haskell.
дан
@dan, Забавно, я нахожу синтаксис Clojure довольно дружелюбным, но это, вероятно, потому, что я раньше был знаком со Scheme. Возможно, после F # я привыкну к тому, как Хаскелл делает вещи.
Работа

Ответы:

16

Давайте сначала проведем различие между изучением абстрактных понятий и изучением конкретных примеров из них.

Вы не будете слишком далеко игнорировать все конкретные примеры по той простой причине, что они совершенно вездесущи. Фактически, абстракции существуют в значительной степени потому, что они объединяют то, что вы будете делать в любом случае с конкретными примерами.

С другой стороны, сами абстракции, безусловно, полезны , но в них нет необходимости. Вы можете довольно далеко проигнорировать абстракции полностью и просто использовать различные типы напрямую. Вы захотите понять их в конце концов, но вы всегда можете вернуться к этому позже. На самом деле, я почти гарантирую, что если вы сделаете это, когда вернетесь к этому, вы будете бить себя по лбу и удивляться, почему вы потратили все это время на трудный путь, вместо того, чтобы использовать удобные инструменты общего назначения.

Взять хотя Maybe aбы пример. Это просто тип данных:

data Maybe a = Just a | Nothing

Это все, кроме самодокументирования; это необязательное значение. Либо у вас «просто» что-то типа a, либо у вас ничего нет. Допустим, у вас есть какая-то функция поиска, которая возвращает Maybe Stringпредставление для поиска Stringзначения, которое может отсутствовать. Таким образом, вы сопоставляете шаблон со значением, чтобы увидеть, какое оно:

case lookupFunc key of
    Just val -> ...
    Nothing  -> ...

Это все!

На самом деле, вам больше ничего не нужно. Нет Functors или Monads или что-нибудь еще. Они выражают общие способы использования Maybe aценностей ... но это просто идиомы, "шаблоны проектирования", как бы вы это ни называли.

Единственное место, где вы действительно не можете избежать этого IO, - это таинственный черный ящик, так что не стоит пытаться понять, что это значит как-то Monadили что-то еще.

На самом деле, вот шпаргалка для всего, что вам действительно нужно знать IOна данный момент:

  • Если у чего-то есть тип IO a, это означает, что это процедура , которая что-то делает и выплевывает aзначение.

  • Когда у вас есть блок кода с использованием doнотации, напишите что-то вроде этого:

    do -- ...
       inp <- getLine
       -- etc...
    

    ... означает выполнить процедуру справа от <-и назначить результат имени слева.

  • Тогда как если у вас есть что-то вроде этого:

    do -- ...
       let x = [foo, bar]
       -- etc...
    

    ... это означает присвоение значения простого выражения (не процедуры) справа от =имени имени слева.

  • Если вы поместите что-то туда без присвоения значения, вот так:

    do putStrLn "blah blah, fishcakes"
    

    ... это означает выполнение процедуры и игнорирование всего, что она возвращает. Некоторые процедуры имеют тип IO ()- ()тип является своего рода заполнителем, который ничего не говорит, так что это просто означает, что процедура что-то делает и не возвращает значение. Вроде какvoid функция в других языках.

  • Выполнение одной и той же процедуры более одного раза может дать разные результаты; это своего рода идея. Вот почему нет способа «удалить» значение IOиз значения, потому что что-то IOне является значением, это процедура для получения значения.

  • Последняя строка в doблоке должна быть простой процедурой без присваивания, где возвращаемое значение этой процедуры становится возвращаемым значением для всего блока. Если вы хотите, чтобы возвращаемое значение использовало какое-то уже присвоенное значение, returnфункция принимает простое значение и дает вам неоперативную процедуру, которая возвращает это значение.

  • В этом нет ничего особенного IO; эти процедуры на самом деле представляют собой простые значения, и вы можете передавать их и комбинировать по-разному. Только когда они выполняются в doблоке, вызванном где-то main, они делают что-либо.

Итак, в чем-то вроде этого совершенно скучного, стереотипного примера программы:

hello = do putStrLn "What's your name?"
           name <- getLine
           let msg = "Hi, " ++ name ++ "!"
           putStrLn msg
           return name

... вы можете прочитать его, как императивную программу. Мы определяем процедуру с именем hello. При выполнении сначала выполняется процедура для печати сообщения с вашим именем; затем он выполняет процедуру, которая читает строку ввода и присваивает результат name; затем он присваивает выражение имени msg; тогда это печатает сообщение; затем он возвращает имя пользователя как результат всего блока. Поскольку nameэто a String, это означает, что helloэто процедура, которая возвращает a String, поэтому она имеет тип IO String. И теперь вы можете выполнить эту процедуру в другом месте, так же, как она выполняетgetLine .

Пффф, монады. Кому они нужны?

CA Макканн
источник
2
@dan: Всегда пожалуйста! Если у вас есть какие-то конкретные вопросы по пути, не стесняйтесь спрашивать о переполнении стека. Тег [haskell] обычно довольно активен, и если вы объясните, откуда вы пришли, люди довольно хорошо помогут вам понять, а не просто бросать загадочные ответы.
CA McCann
9

Насколько важны передовые концепции Haskell, такие как монады и аппликативные функторы, для большинства рутинных задач программирования?

Они необходимы. Без них слишком просто использовать Haskell в качестве еще одного императивного языка, и хотя Саймон Пейтон Джонс однажды назвал Haskell, «лучший в мире язык императивного программирования», вы все равно упускаете лучшую часть.

Монады, преобразования монад, моноиды, функторы, аппликативные функторы, контравариантные функторы, стрелки, категории и т. Д. Являются шаблонами проектирования. Как только вы вписываете конкретную вещь, которую вы делаете, в одну из них, вы можете использовать огромное количество функций, написанных абстрактно. Эти классы не просто сбивают вас с толку, они делают вашу жизнь проще и продуктивнее. Они, на мой взгляд, являются основной причиной краткости хорошего кода на Haskell.

dan_waterworth
источник
1
+1: Спасибо за указание на то, что «Монады, преобразования монад, моноиды, функторы, аппликативные функторы, контравариантные функторы, стрелки, категории и т. Д. Являются шаблонами проектирования». !
Джорджио
7

Строго ли это необходимо, если вы просто хотите запустить что-то? Нет.

Нужно ли это, если вы хотите писать красивые идиоматические программы на Haskell? Абсолютно.

При программировании на Haskell полезно помнить две вещи:

  1. Система типов поможет вам. Если вы составляете свою программу из очень полиморфного кода, насыщенного типами, очень часто вы можете попасть в удивительную ситуацию, когда тип функции, которую вы хотите, приведет вас к (единственной!) Правильной реализации .

  2. Различные доступные библиотеки были разработаны с использованием принципа # 1.

Поэтому, когда я пишу программу на Haskell, я начинаю с написания типов. Затем я начинаю заново и записываю некоторые более общие типы (и, если они могут быть экземплярами существующих классов типов, тем лучше). Затем я пишу некоторые функции, которые дают мне значения типов, которые я хочу. (Затем я играю с ними ghciи, возможно, напишу несколько тестов quickCheck.) И, наконец, я склеиваю все это вместе main.

Можно написать уродливый Haskell, который просто запускает что-то. Но есть еще много чего, когда вы достигнете этой стадии.

Удачи!

Lambdageek
источник
1
Спасибо! Я колебался между Clojure и Haskell, но теперь я склоняюсь к Haskell из-за того, насколько полезными были такие люди, как вы.
дан
1
Сообщество Haskell кажется очень хорошим и полезным. И, похоже, именно отсюда приходит много интересных идей
Захари К