Этот оператор настолько важен, что он присутствует в логотипе языка Haskell.
Оператор bind это функция двух аргументов:
Оператор bind это функция двух аргументов:
- аргумент a упакован в монадический контейнер;
- стрелка Клейсли из a в m b.
И возвращает нам в качестве значения монадический контейнер, только в него упаковано значение b.
Идея оператора bind заключается в том, что он должен для каждой конкретной монады вынуть из монадического контейнера значение a и передать его в стрелку Клейсли и вернуть ее значение. Оператор монадического связывания он как раз связывает два монадических вычисления.
Оператор монадического связывание имеет низкий первый приоритет и левую ассоциативность.
Оператор доллар просто брал функцию и аргумент и применял функцию к аргументу:
Он был правоассоциативен и имел низкий приоритет.
Функция & повторяет оператор $ но просто с переставленными аргументами:
Давайте посмотрим как эти цепочки работают на некоторых простых примерах:
Prelude> (+1) $ (*3) $ (+2) $ 5
22
Prelude> 5 & (+2) & (*3) & (+1)
Идея оператора bind заключается в том, что он должен для каждой конкретной монады вынуть из монадического контейнера значение a и передать его в стрелку Клейсли и вернуть ее значение. Оператор монадического связывания он как раз связывает два монадических вычисления.
Оператор монадического связывание имеет низкий первый приоритет и левую ассоциативность.
Оператор доллар просто брал функцию и аргумент и применял функцию к аргументу:
Он был правоассоциативен и имел низкий приоритет.
Функция & повторяет оператор $ но просто с переставленными аргументами:
Давайте посмотрим как эти цепочки работают на некоторых простых примерах:
Prelude> (+1) $ (*3) $ (+2) $ 5
22
Prelude> 5 & (+2) & (*3) & (+1)
22
Если стереть буковку m, то наш bind работает точно также как и &.
С другой стороны оператор монадического связывания bind похож на функцию fmap с переставленными аргументами:
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> :t flip fmap
flip fmap :: Functor f => f a -> (a -> b) -> f b
Каждая монада является функтором. В случае fmap наша функция не меняет структуру контейнера. А оператор монадического связывания вполне может изменить структуру контейнера. Потому что функция (a -> m b) знает что-то о контейнере и для каждого контейнера она своя и соответственно она может выполнять гораздо более глубокие изменения внутри контейнерного типа нежели fmap.