Точка путаницы верхнего уровня, я думаю: flip
модифицирует arb
, а не модифицирует <*>
, как вы, кажется, верите. Мы «изменили» <*>
, чтобы иметь «правильный» порядок аргументов, просто передав <*>
свои аргументы в обратном порядке, мы их получили!
Теперь для деталей. У нас, как вы отметили:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
Итак, с левой стороны написано
ra >>= arb = ...
то, что мы имеем в области видимости:
ra :: r -> a
arb :: a -> r -> b
(Обратите внимание, как имена были выбраны, чтобы отразить типы!) Переписав тип, который вы дали для flip
, мы имеем
flip :: (a -> b -> c) -> b -> a -> c -- original
flip :: (a -> r -> b) -> r -> a -> b -- rename variables
отсюда:
flip arb :: r -> a -> b
Теперь вспомните тип (<*>)
, который вы написали:
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
Итак, для первого аргумента (<*>)
мы хотим что-то типа r -> a -> b
. Привет! flip arb
имеет такой тип! Для второго аргумента нам нужно что-то типа r -> a
. И нам снова повезло, потому что ra
имеет такой тип, так что ...
flip arb <*> ra :: r -> b
(Как обычно с инфиксными операторами, это применение оператора (<*>)
с аргументами flip arb
и ra
.) Какой тип мы надеялись получить? Ну, теперь мы возвращаемся к типу (>>=)
:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
После получения двух аргументов предполагается, что он возвращает что-то типа r -> b
. Круто, вот что мы построили.
ra >>= arb = flip arb <*> ra