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

Функция >return для монады >Maybe определена как вызов конструктора >Just. Вся суть монады >Maybe состоит в возможном неуспехе в вычислениях, и если у нас есть значение, которое мы хотим поместить в такой контекст, есть смысл в том, чтобы обрабатывать его как успешное вычисление, поскольку мы знаем, каким является значение. Вот некоторые примеры использования функции >return с типом >Maybe:

>ghci> return 3 >>= (\x –> Just (x+100000))

>Just 100003

>ghci> (\x –> Just (x+100000)) 3

>Just 100003

Для списковой монады функция >return помещает что-либо в одноэлементный список. Реализация операции >>>= для списков проходит по всем значениям в списке и применяет к ним функцию. Однако, поскольку в одноэлементном списке лишь одно значение, это аналогично применению функции к данному значению:

>ghci> return "WoM" >>= (\x –> [x,x,x])

>["WoM","WoM","WoM"]

>ghci> (\x –> [x,x,x]) "WoM"

>["WoM","WoM","WoM"]

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

Правая единица

Второй закон утверждает, что если у нас есть монадическое значение и мы используем операцию >>>= для передачи его функции >return, результатом будет наше изначальное монадическое значение. Формально >m >>= return является не чем иным, как просто >m.

Этот закон может быть чуть менее очевиден, чем первый. Давайте посмотрим, почему он должен выполняться. Когда мы передаём монадические значения функции, используя операцию >>>=, эти функции принимают обычные значения и возвращают монадические. Функция >return тоже является такой, если вы рассмотрите её тип.

Функция >return помещает значение в минимальный контекст, который по-прежнему возвращает это значение в качестве своего результата. Это значит, что, например, для типа >Maybe она не вносит никакого неуспеха в вычислениях; для списков – не вносит какую-либо дополнительную недетерминированность.

Вот пробный запуск для нескольких монад:

>ghci> Just "двигайся дальше" >>= (\x –> return x)

>Just "двигайся дальше"

>ghci> [1,2,3,4] >>= (\x –> return x)

>[1,2,3,4]

>ghci> putStrLn "Вах!" >>= (\x –> return x)

>Вах!

В этом примере со списком реализация операции >>>= выглядит следующим образом:

>xs >>= f = concat (map f xs)

Поэтому когда мы передаём список >[1,2,3,4] функции >return, сначала она отображает >[1,2,3,4], что в результате даёт список списков >[[1],[2],[3],[4]]. Затем это конкатенируется, и мы получаем наш изначальный список.