Я получал то же сообщение об ошибке. Проблема возникла только тогда, когда Flash сделал вызов ExternalInterface, который был возвращен после сбоя Flash (по какой причине вообще). Исправление, которое я реализовал, было: Проверьте, все еще запущен и запущен Flash-объект, и если обратный вызов все еще является функцией этого объекта.
Ваши описания кажутся довольно хорошими. Обычно люди говорят о трех законах монады, которые у вас обозначены как 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
должен иметь идентичное поведение с обеих сторон оператора bind.
Теперь о третьем законе. Этот закон по сути говорит, что и экземпляр Functor, и ваш экземпляр Monad ведут себя одинаково, когда поднимают функцию в монаду, и что ни один из них не делает ничего монадического. Если я не ошибаюсь, то когда монада подчиняется трем другим законам, а экземпляр Functor подчиняется законам functor, то это утверждение всегда будет истинным.
Многое из этого взято из Haskell Wiki. Typeclassopedia также является хорошим справочником.
С другими ответами не спорю, но, возможно, стоит подумать о том, что законы монады на самом деле описывают два набора свойств. Как говорит Джон, третий закон, который вы упоминаете, немного отличается, но вот как можно разделить остальные:
Как и в ответе Джона, то, что называется стрелкой Клейсли для монады - это функция с типом 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)
Эти три закона описывают до смешного общий паттерн, который Haskell, к сожалению, не может выразить в полной общности. Если вам интересно, Control.Category
дает обобщение "вещей, которые выглядят как композиция функций", а Data.Monoid
обобщает последний случай, когда не задействованы параметры типа.
Первые три закона гласят, что «return» только обертывает значение и больше ничего не делает. Таким образом, вы можете исключить «обратные» вызовы без изменения семантики.
Последний закон - ассоциативность для связывания. Это означает, что вы берете что-то вроде:
do
x <- foo
bar x
z <- baz
и превращаете его в
do
do
x <- foo
bar x
z <- baz
, не меняя значения. Конечно, вы бы точно этого не сделали, но вы можете поместить внутреннее предложение do в оператор if и захотеть, чтобы оно означало то же самое, когда «if» истинно.
Иногда монады не подчиняются в точности этим законам, особенно когда возникает какое-то нижнее значение. Это нормально, если оно задокументировано и является «морально правильным» (то есть соблюдаются законы для не нижних значений, или результаты считаются эквивалентными каким-либо другим образом).
В терминах нотации do
правило 4 означает, что мы можем добавить дополнительный блок do
для группировки последовательности монадических операции.
do do
y <- do
x <- m x <- m
y <- k x <=> k x
h y h y
Это позволяет функциям, возвращающим монадическое значение, работать правильно.