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

Второй закон утверждает, что если у нас есть монадическое значение и мы используем операцию >>= для передачи его функции 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]]. Затем это конкатенируется, и мы получаем наш изначальный список.

Левое тождество и правое тождество являются, по сути, законами, которые описывают, как должна вести себя функция return. Это важная функция для превращения обычных значений в монадические, и было бы нехорошо, если бы монадическое значение, которое она произвела, имело больше, чем необходимый минимальный контекст.