Левая единица
Первый закон монад утверждает, что если мы берём значение, помещаем его в контекст по умолчанию с помощью функции 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.