Изучай Haskell во имя добра! (Липовача) - страница 234

не была бы столь полезна: после первого применения контекст был бы утрачен.

Давайте попробуем передать функции недетерминированное значение:

>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, мы можем сцеплять несколько списков с помощью операции >>>=, распространяя недетерминированность: