Может быть, следующее будет более ярким, вместо этого:
flip mapT :: (Traversable t, Monad m) => t a -> (a -> m b) -> t (m b)
sequenceA :: (Traversable t, Monad m) => t (m b) -> m (t b)
flip mapM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
flip liftM :: Monad m => m a -> (a -> m b) -> m (m b)
join :: Monad m => m (m b) -> m b
(join .) . flip liftM :: Monad m => m a -> (a -> m b) -> m b
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(с использованием некоторых более специализированных типов, чем самые общие, здесь и там; также с переименованным mapT f = runIdentity . traverse (Identity . f)
).
Ваш конкретный вопрос менее интересен. Тип деривации является полностью механическим процессом. Некоторые сущности должны быть совместимыми, чтобы все выражение имело смысл, поэтому их типы должны объединяться:
(join . mapM) a_mb x = -- a_mb :: a -> m b
= join (mapM a_mb) x
= join ta_mtb x -- ta_mtb :: t a -> m (t b)
Чтобы присоединиться к функции, нужно вызвать ее дважды,
= ta_mtb x x
, что означает x
- это t a
, поэтому m
- это t a ->
:
x :: t a
ta_mtb :: t a -> m (t b)
----------------------------
ta_mtb x :: m (t b)
~ t a -> t b
x :: t a
----------------------------
ta_mtb x x :: t b
, таким образом a_mb :: a -> m b ~ a -> t a -> b
.