这源于>>= 是如何为((->) r) 类型定义的:
(f =<< g) x = f (g x) x
这样
(>>=) id (+) 3
=
(id >>= (+)) 3
=
((+) =<< id) 3
=
(+) (id 3) 3
=
3 + 3
查看类型:
> :t let (f =<< g) x = f (g x) x in (=<<)
let (f =<< g) x = f (g x) x in (=<<)
:: (t1 -> (t2 -> t)) -> (t2 -> t1) -> (t2 -> t)
> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
类型匹配
t1 ~ a
(t2 ->) ~ m -- this is actually ((->) t2)`
t ~ b
因此,这里的约束Monad m 表示Monad ((->) t2),它定义了=<< 和>>= 的定义,它们会被使用。
如果要从类型推导出定义,
(>>=) :: Monad m => m a -> (a -> m b) -> m b
m ~ ((->) r)
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
(>>=) f g r = b
where
a = f r
rb = g a
b = rb r
简化后就是我们上面使用的那个。
如果你想“用文字”来理解它,
(=<<) :: (Monad m, m ~ ((->) r)) => (a -> m b) -> m a -> m b
(f =<< g) x = f (g x) x
-
g 是“可以计算”“a”的“一元值”,表示为r -> a
-
f a 计算“可以计算”“b”的“一元值”,表示为r -> b,
- 因此
\x -> f (g x) x 是一个单子值,“可以计算”一个“b”,给定一个“r”。
所以这些“非单子函数”实际上是单子值,恰好是函数。
因此,在您的示例中,g = id、f = (+) 和
-
id 是“可以计算”“a”的“一元值”,a -> a
-
(+) a 计算一个“单子值”,“可以计算”一个“b”,一个a -> b,其中b 实际上也是一个a,
- 因此
\x -> (+) (id x) x 是一个“可以计算”“a”的单子值,给定一个“a”:
(>>=) id (+)
=
((+) =<< id)
=
\x -> (+) (id x) x
=
\x -> (+) x x