2015-03-09 2 views
1

Я читал некоторые документы в Интернете, которые пытались представить концепцию монады для программистов Схемы. Основная идея заключалась в том, что в неимперативном программировании монады используются для выражения «потока вычислений», то есть для обеспечения последовательной оценки выражений. Тогда это поразило меня: поскольку тело лямбда-выражения оценивается последовательно, нужно ли понимать, что монады будут излишними в Схеме? Являются ли лямбда-тела по-разному оценены на других языках (например, Haskell или ML)?Лямбда выражения как монады в схеме?

+9

Документы, которые вы читали, скорее всего, вводят в заблуждение. Монады - очень абстрактная идея, и, к сожалению, абстрактные идеи привлекают всевозможные непреднамеренные дезинформации. Я не хочу сам объяснять это и потенциально способствовать большей путанице (поэтому я не хочу писать полный ответ), поэтому я просто свяжу вас с хорошо расцененной статьей для создания интуиции о монадах: [«Вы могли бы придумать монады! (и, возможно, у вас уже есть.)»] (http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html) , –

+1

Не совсем. Монады могут использоваться для немого секвенирования, но они больше о том, что происходит * между * каждой операцией, чем сама секвенция (они называются «программируемыми точками с запятой»). Однако статья @ Тихона - замечательная, и я определенно рекомендую ее. –

ответ

5

Последовательная оценка

Таким образом, последовательное вычисление выражения не характерно для монады, но функций. С того момента, как вы напишете f (g x) (Haskell) или (f (g x)) (Схема), вы определили g, как это происходит до f. В Haskell мы вместо этого делаем это с операторами секвенирования, такими как (then f g) и (bind f (lambda (x) (make-g x))), но вы можете сделать это, как хотите.

Путаница: монады имеют общую нотацию в Haskell по крайней мере, и эта общая нотация ставит утверждения в императивном порядке. С точки зрения схемы это макрос do, который переписывает:

(do 
    (put-string "Hey, what's your name?") 
    (into x get-line) 
    (put-string (string-append "Hi, " x "!"))) 

в

(then 
    (put-string "Hey, what's your name?") 
    (bind get-line (lambda (x) 
     (put-string (string-append "Hi, " x "!"))))) 

Обратите внимание, что лямбды получить «сглаженный» и заменить каким-то новым символом «в». (На самом деле в Haskell мы бы сказали, «от», но это оператор инфикса, а не оператор префикса.)

Что монады

Так что является монадой, на самом деле? Ну, во-первых, давайте определим их часть речи: монады - это прилагательные, как прилагательное «синий». У меня может быть синий вагон или синее колесо. Monads functors, что означает, что с учетом функции от вагонов до их колес я могу дать вам функции от синий вагоны к их синий колеса. Таким образом, функции могут «работать под ними». Но монады имеют два специальных свойства. Сначала у нас есть идея, которая применима только к «синим», если мы сделаем идею необычно абстрактной и метафизической.: прилагательное должно быть , которое может быть применено к любому значению на этом языке. Таким образом, у вас есть не только синие вагоны и синие колеса, но и синие функции, синие программы, которые печатают «Hello, World!». на экран, все синее. Второй из прилагательного должен быть конденсируемым в том смысле, что данный синий синий вагон, вы можете просто дать мне синий вагон.

Одно прилагательное, которое делает это «обнуляемым ...». Вы всегда можете взять любое значение и создать на нем новое значение с нулевым значением: просто начните принимать и обнаруживать нулевые значения! Если вы находитесь на статически типизированном языке, где по умолчанию значения по умолчанию не равны нулю, это важно. Это прилагательное является функтором: при задании функции мы просто преобразуем null в нуль и все, что мы преобразуем с помощью функции. Это конденсируемо, потому что, если у нас есть «нулевая нулевая строка», которая сводится к нулевой строке: возьмите значения «null» и «not-null null» в «null» и «not-null not-null string» на «null», not-null string ". Наконец, чтобы представить любую строку как нулевую строку, преобразуйте ее в «непустую строку».Это называется монадой Maybe. Это на самом деле специализированный случай монады Either y, который может содержать y.

Другое прилагательное, которое делает это «список ...». Чтобы применить функцию под прилагательным, примените ее ко всем членам списка. Чтобы сконденсировать список списков в список, объедините его элементы. Чтобы создать список x из любого x, верните мне список из одного элемента. Это называется «монадой списка». Написание этого способа очень похоже на понимание списков списков, и на самом деле оно изоморфно Clojure-преобразователям, поэтому вы получаете бесплатно фильтры &.

Другое прилагательное, которое делает это «функцией от s до s и a ...». Чтобы создать один из них из любого x, просто соедините входящее состояние с x. Чтобы применить функцию, просто примените ее к соответствующей стороне выходной пары. Очень просто. Наконец, если у вас есть свернутая ситуация s -> (s, s -> (s, a)), постройте s -> (s, a), подав входящие s на свернутую функцию, взяв s, который выходит из этого, и подает его на s -> (s, a), который выходит из него. Это даст вам (s, a), который вам нужно вернуть. Это называется «Монастырь State s», потому что вы можете представить «s» как типизированное состояние.

Другое прилагательное, которое делает это «программа, которая возвращает». Если у вас есть int, мы можем построить программу, которая ничего не делает и возвращает int. Если у вас есть программа, которая возвращает int и функцию от ints к чему-то еще, мы можем сделать программу, а затем применить функцию к выходу программы. Наконец, если у вас есть «программа, которая возвращает программу, которая возвращает int», просто создайте программу, которая запускает внешнюю программу для вычисления внутренней, а затем запускает внутреннюю. Это называется монадой IO x. (Аналогично обещаниям: обещанный обещанный x мало чем отличается от обещанного x.)

Вы можете видеть, что это очень широкий шаблон, и он не всегда четко подразумевает «последовательность».

Сравнивая схемы с Haskell

После того, как вы понимаете, что Haskell описывает все свои операции ввода/вывода, содержащий программы в качестве значений, а затем объединить их вместе, вы понимаете, что в основном мы делаем функционал I/O, став макроязык. Язык макросов не делает любой I/O сам по себе, но вы используете его для создания программ, которые делают для вас ввод/вывод. Вы кормите их в компилятор, а компилятор создает фактическую программу, которая делает то, что вы хотите. Интерпретаторы получают немного более рискованно, потому что интерпретатор должен сказать «если я вижу значение, которое не является программой, я попытаюсь напечатать это, если я вижу значение, которое - это, программа, я попытаюсь запустить эту программу и затем распечатайте это ». Это означает, что синтаксис в командной строке тонко отличается от синтаксиса в файле.

Как только вы понимаете, что Haskell является средой метапрограммирования, в которой мы строим программу как ценность, вы поймете, как Haskell выполняет функциональные операции ввода-вывода, и вы увидите программируемый синтаксис для «monads» as мета-метапрограммирование. Этот дизайн гораздо менее сложный, чем макросы (которые мы также имеем в Haskell, это называется «Template Haskell»), но выполняет работу для множества полезных случаев. И по существу, о перегрузке на каком-то уровне, что «a; b; c; d» означает быть зависимым от (общего) внешнего прилагательного типов a, b, c и d. Для ввода/вывода это означает «сделать a, затем сделать b, затем ...»; для состояний это означает «поток состояния, созданного а в b, тогда состояние, созданное b в c, затем ...»; для nullables это означает «сделать a, если это не является нулевым, использовать его для b, если это не пустое использование для выполнения c ...».Для списков это декартово произведение составляющих списков, «соберите все по всем путям».

Смежные вопросы