не была бы столь полезна: после первого применения контекст был бы утрачен.
Давайте попробуем передать функции недетерминированное значение:
>ghci> [3,4,5] >>= \x –> [x,-x]
>[3,-3,4,-4,5,-5]
Когда мы использовали операцию >>>=
со значениями типа >Maybe
, монадическое значение передавалось в функцию с заботой о возможных неудачах. Здесь она заботится за нас о недетерминированности.
Список >[3,4,5]
является недетерминированным значением, и мы передаём его в функцию, которая тоже возвращает недетерминированное значение. Результат также является недетерминированным, и он представляет все возможные результаты получения элементов из списка >[3,4,5]
и передачи их функции >\x –> [x,–x]
. Эта функция принимает число и производит два результата: один взятый со знаком минус и один неизменный. Поэтому когда мы используем операцию >>>=
для передачи этого списка функции, каждое число берётся с отрицательным знаком, а также сохраняется неизменным. Образец >x
в анонимной функции принимает каждое значение из списка, который ей передаётся.
Чтобы увидеть, как это достигается, мы можем просто проследить за выполнением. Сначала у нас есть список >[3,4,5]
. Потом мы отображаем его с помощью анонимной функции и получаем следующий результат:
>[[3,-3],[4,-4],[5,-5]]
Анонимная функция применяется к каждому элементу, и мы получаем список списков. В итоге мы просто сглаживаем список – и вуаля, мы применили недетерминированную функцию к недетерминированному значению!
Недетерминированность также включает поддержку неуспешных вычислений. Пустой список в значительной степени эквивалентен значению >Nothing
, потому что он означает отсутствие результата. Вот почему неуспешное окончание вычислений определено просто как пустой список. Сообщение об ошибке отбрасывается. Давайте поиграем со списками, которые приводят к неуспеху в вычислениях:
>ghci> [] >>= \x –> ["плохой","бешеный","крутой"]
>[]
>ghci> [1,2,3] >>= \x –> []
>[]
В первой строке пустой список передаётся анонимной функции. Поскольку список не содержит элементов, нет элементов для передачи функции, а следовательно, результатом является пустой список. Это аналогично передаче значения >Nothing
функции, которая принимает тип >Maybe
. Во второй строке каждый элемент передаётся функции, но элемент игнорируется, и функция просто возвращает пустой список. Поскольку функция завершается неуспехом для каждого элемента, который в неё попадает, результатом также является неуспех.
Как и в случае со значениями типа >Maybe
, мы можем сцеплять несколько списков с помощью операции >>>=
, распространяя недетерминированность: