我认为您的问题过于关注价值观。monad 是一个类型构造函数,因此不关心有多少和什么样的值,而只关心上下文。
AMaybe a
可以是a
,也可以什么都不是。很简单,你正确地观察到了这一点。
AnEither String a
要么是 some a
,要么是 a 形式的一些信息String
(例如,为什么计算a
失败)。
最后,[a]
是未知数量的a
s(或根本没有),这可能是由模棱两可的计算产生的,或者是一个给出多个结果的结果(如二次方程)。
现在,对于 的解释(>>=)
,了解 monad 的基本属性(范畴论者如何定义)是有帮助的
join :: m (m a) -> m a.
加上fmap
,(>>=)
可以写成join
。
以下是什么join
意思:一个上下文,再次放在相同的上下文中,仍然具有相同的结果行为(对于这个 monad)。
这一点很明显Maybe (Maybe a)
: 某些东西本质上可以是Just (Just x)
, or Nothing
, or Just Nothing
, 提供与 . 相同的信息Nothing
。因此,Maybe (Maybe a)
您可以不使用 ,Maybe a
而不会丢失任何信息。就是这样join
做的:它转换为“更容易”的上下文。
[[a]]
不知何故更困难,但并不多。从多个/不明确的结果中,您基本上有多个/不明确的结果。一个很好的例子是四次多项式的根,它是通过求解一个二次方程找到的。你首先得到两个解,从每个解中你可以找到另外两个,得到四个根。
但关键是,无论您谈论的是模棱两可的模棱两可的结果,还是只是一个模棱两可的结果。您可以始终使用上下文“模糊”,并使用join
.
这就是(>>=)
列表的作用:它将模棱两可的函数应用于模棱两可的值:
squareRoots :: Complex -> [Complex]
fourthRoots num = squareRoots num >>= squareRoots
可以改写为
fourthRoots num = join $ squareRoots `fmap` (squareRoots num)
-- [1,-1,i,-i] <- [[1,-1],[i,-i]] <- [1,-1] <- 1
因为您所要做的就是为每个可能的值找到所有可能的结果。
这就是为什么join
是concat
列表,事实上
m >>= f == join (fmap f) m
必须在任何单子中成立。
可以给出类似的解释IO
。具有副作用的计算,也可能具有副作用 ( IO (IO a)
),本质上只是具有副作用的东西。