Подтвердить что ты не робот

Объяснение законов Монады

Из нежное введение в Haskell, есть следующие законы монады. Может ли кто-нибудь интуитивно объяснить, что они означают?

return a >>= k             = k a
m >>= return               = m
xs >>= return . f          = fmap f xs
m >>= (\x -> k x >>= h)    = (m >>= k) >>= h

Вот мое объяснение:

  • Мы ожидаем, что возвращаемая функция обернется a, чтобы ее монадическая природа была тривиальной. Когда мы привязываем его к функции, нет никаких монадических эффектов, она должна просто передать a функции.

  • Развернутый вывод m передается для возврата, который переустанавливает его. Монадическая природа остается прежней. Так что это то же самое, что и оригинальная монада.

  • Развернутое значение передается в f, затем перезаписывается. Монадическая природа остается прежней. Это поведение, ожидаемое при преобразовании нормальной функции в монадическую функцию.

  • У меня нет объяснения этого закона. Это говорит о том, что монада должна быть "почти ассоциативной", хотя

4b9b3361

Ответ 1

Ваши описания выглядят неплохо. Как правило, люди говорят о трех монадских законах, которые у вас есть как 1, 2 и 4. Ваш третий закон несколько отличается, и я позабочусь об этом позже.

Для трех законов монады мне гораздо легче получить интуитивное понимание того, что они означают, когда они переписаны с использованием композиции Клейсли:

-- defined in Control.Monad
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
mf >=> n = \x -> mf x >>= n

Теперь законы могут быть записаны как:

1) return >=> mf = mf                  -- left identity
2) mf >=> return = mf                  -- right identity
4) (f >=> g) >=> h = f >=> (g >=> h)   -- associativity

1) Закон левой идентичности - возврат значения не изменяет значение и ничего не делает в монаде.

2) Право прав личности - возврат значения не изменяет значение и ничего не делает в монаде.

4) Ассоциативность - монадическая композиция ассоциативна (мне нравится ответ KennyTM для этого)

Два закона идентичности в основном говорят одно и то же, но они оба необходимы, потому что return должно иметь поведение идентичности с обеих сторон оператора привязки.

Теперь для третьего закона. Этот закон по сути говорит, что и экземпляр Functor, и ваш экземпляр Monad ведут себя одинаково, когда поднимают функцию в монаду, и что она не делает ничего монадического. Если я не ошибаюсь, то случай, когда монада подчиняется другим трем законам, и экземпляр Functor подчиняется законам функтора, тогда это утверждение всегда будет истинным.

Многое из этого происходит из Haskell Wiki. Typeclassopedia также является хорошей ссылкой.

Ответ 2

Никаких разногласий с другими ответами, но это могло бы помочь думать о законах монады, как фактически описывая два набора свойств. Как говорит Джон, третий закон, который вы упоминаете, немного отличается, но здесь, как другие могут быть разделены:

Функции, которые вы связываете с монадой, составлены так же, как обычные функции.

Как и в ответе Джона, так называемая стрелка Клейсли для монады - это функция с типом a -> m b. Подумайте о return как id и (<=<) как (.), а законы монады - их переводы:

  • id . f эквивалентен f
  • f . id эквивалентен f
  • (f . g) . h эквивалентен f . (g . h)

Последовательности монадических эффектов добавляются как списки.

По большей части вы можете думать о дополнительной монадической структуре как о последовательности дополнительных действий, связанных с монадическим значением; например Maybe "сдаваться" для Nothing и "продолжать движение" для Just. Объединение двух монадических действий затем по существу объединяет последовательности поведения, которые они проводили.

В этом смысле return снова является тождеством - нулевое действие, похожее на пустой список поведения, и (>=>) является конкатенацией. Итак, монадские законы являются их переводами:

  • [] ++ xs эквивалентно xs
  • xs ++ [] эквивалентен xs
  • (xs ++ ys) ++ zs эквивалентен xs ++ (ys ++ zs)

Эти три закона описывают смехотворно общую картину, которую Хаскелл, к сожалению, не может выразить в полной общности. Если вам интересно, Control.Category дает обобщение "вещей, которые выглядят как состав функций", а Data.Monoid обобщает последний случай, когда не задействованы никакие параметры типа.

Ответ 3

В терминах обозначения do правило 4 означает, что мы можем добавить дополнительный блок do для группировки последовательности монадических операций.

    do                          do
                                  y <- do
      x <- m                             x <- m
      y <- k x          <=>              k x
      h y                         h y

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

Ответ 4

Первые три закона говорят, что "возврат" только обертывает значение и ничего не делает. Таким образом, вы можете исключить "возвратные" вызовы без изменения семантики.

Последний закон - ассоциативность связывания. Это означает, что вы берете что-то вроде:

do
   x <- foo
   bar x
   z <- baz

и превратите его в

do
   do
      x <- foo
      bar x
   z <- baz

без изменения значения. Конечно, вы не сделали бы этого, но вы можете поместить внутреннее предложение do в оператор "if" и хотите, чтобы это означало то же самое, когда "if" истинно.

Иногда монады точно не следуют этим законам, особенно когда происходит какое-то нижнее значение. Это нормально, пока оно задокументировано и является "морально правильным" (т.е. Законы соблюдаются для не-нижних значений или результаты считаются эквивалентными каким-либо другим способом).