Интересное бит я предполагаю, это:
toss2Dice = do
n <- tossDie
m <- tossDie
return (n+m)
Это несколько эквивалентно следующий Python:
def toss2dice():
for n in tossDie:
for m in tossDie:
yield (n+m)
Когда дело доходит до списка монады, вы можете просмотреть обязательные стрелки (<-
) в обозначении как традиционные императивные «foreach» петли. Все, после
n <- tossDie
принадлежит к «телу цикла» этого Еогеасп цикла, и так будет оцениваться один раз для каждого значения в tossDie
присвоенного n
.
Если вы хотите desugaring от do
записи фактических операторов связывания >>=
, это выглядит следующим образом:
toss2Dice =
tossDie >>= (\n ->
tossDie >>= (\m ->
return (n+m)
)
)
Обратите внимание, как «внутреннее тело цикла»
(\n ->
tossDie >>= (\m ->
return (n+m)
)
)
Получит выполняется один раз для каждое значение в tossDie
. Это в значительной степени эквивалентно вложенным петлям Python.
Технический фетиш: Причина вы получаете «Еогеасп» петли от связывания стрелок должен делать с конкретной монады вы работаете. Стрелки означают разные вещи для разных монадов, и чтобы знать, что они означают для определенной монады, вам нужно немного поработать и понять, как эта монада работает вообще.
Стрелков получают обессахаренную в вызовы оператора связывания, >>=
, который работает по-разному для разных монад, а также - это причина, по которой связывает стрелки <-
также работают по-разному для разных монад!
В случае монады списка оператор привязки >>=
берет список влево и функцию, возвращающую список справа, и сортировка применяет эту функцию к каждому элементу списка.Если мы хотим, чтобы удвоить каждый элемент в списке в громоздкой образом, мы могли бы представить себе это делать, как
λ> [1, 2, 3, 4] >>= \n -> return (n*2)
[2,4,6,8]
(return
требуется, чтобы типы работать. >>=
ожидает функцию, которая возвращает список, и return
будет, для списка монады, оберните значение в списке.) для того, чтобы проиллюстрировать, возможно, более мощный пример, мы можем начать воображать функцию
λ> let posneg n = [n, -n]
λ> posneg 5
[5,-5]
Тогда мы можем написать
λ> [1, 2, 3, 4] >>= posneg
[1,-1,2,-2,3,-3,4,-4]
считать натуральные числа от -4 до 4.
Причины список монада работает таким образом, что это Конкретное поведение привязки оператора >>=
и return
делает монаду законы держать. Законы монады важны для нас (и, возможно, авантюрного компилятора), потому что они позволяют нам менять код так, как мы знаем, ничего не сломают.
Очень милый побочный эффект от этого заключается в том, что он делает списки очень удобными для представления неопределенности в значениях. Скажем, вы создаете объект OCR, который должен смотреть на изображение и превращать его в текст. Вы можете столкнуться с символом, который может быть либо 4, либо A или H, но вы не уверены. Позволив OCR thingey работать в списке монады и вернет список ['A', '4', 'H']
, вы применили свои базы. Фактически работа со сканированным текстом становится очень простой и читаемой с помощью do
нотации для монады списка. (Это Сорт выглядит, как вы работаете с одиночными значениями, когда на самом деле вы просто генерировать все возможные комбинации!)
Вы уже знаете, что означают дескрипторы 'do'? – leftaroundabout
Да, я думаю, я понимаю эту часть - вот как я выясняю, откуда «м». Но, очевидно, я недостаточно понимаю :) – Arkadiy
это просто 'tossDie >> = (\ n -> tossDie >> = (\ m -> return (n + m)))' –