Функция >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]]
. Затем это конкатенируется, и мы получаем наш изначальный список.