Левая единица

Первый закон монад утверждает, что если мы берём значение, помещаем его в контекст по умолчанию с помощью функции return, а затем передаём его функции, используя операцию >>=, это равнозначно тому, как если бы мы просто взяли значение и применили к нему функцию. Говоря формально, return x >>= f – это то же самое, что и f x.

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

Функция 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.