我描述了四种信息来源,您可以使用它们来了解>>=
特定 monad 的行为。
的类型>>=
的类型>>=
始终相同。它在Monad
类型类中指定。请参阅文档。类型是:
(>>=) :: forall a b. m a -> (a -> m b) -> m b
您感兴趣的特定 monad 的占位符在哪里m
。例如,对于列表 monad,其类型>>=
为:
(>>=) :: forall a b. [a] -> (a -> [b]) -> [b]
请注意,我刚刚替换m ...
为[...]
.
单子定律
每个 monad的实现>>=
都不同,但所有 monad 都应该遵守 monad 法则。这些定律在Monad
类型类的文档中指定。再次查看文档。法律是:
return a >>= k == k a
m >>= return == m
m >>= (\x -> k x >>= h) == (m >>= k) >>= h
因此,无论某些特定 monad 的实现可能是什么,您都可以使用这些定律来推理您的代码。例如,如果您的代码包含类似法律左侧的代码,您可以用相应的法律右侧的代码替换该代码,并且行为不应改变。
这是一个如何使用单子定律的示例。假设我写了这段代码:
foo = do
x <- bar
return x
我们甚至不知道这里使用了什么 monad,但我们知道有一些 monad,因为我们看到了 do 表示法。要应用 monad 法则,我们必须对调用的 do 表示法去糖>>=
:
foo = bar >>= (\x -> return x)
请注意,\x -> return x
这与 just 相同return
(通过 η-reduction.
foo = bar >>= return
根据第二个单子定律,这段代码与调用 bar 的含义完全相同。
foo = bar
所以看起来好像>>=
原始foo
函数中的 根本不能做任何有趣的事情,因为单子定律允许我们把它排除在外。我们甚至不知道>>=
这里的操作员提供了什么特定的 monad 就知道了。
特定单子的文档
如果您需要了解有关特定 monad 的行为的更多信息,>>=
特定 monad 的文档应该会告诉您。您可以使用hoogle搜索文档。例如,文档StateT
告诉您:
该return
函数保持状态不变,同时>>=
使用第一次计算的最终状态作为第二次计算的初始状态。
特定monad的实现
如果您想了解有关特定 monad 实现的更多细节,您可能必须查看实际实现。搜索instance Monad ...
声明。例如,查看. StateT
list monad 的实现在这个文件的某个地方,搜索instance Monad []
或查看这个,除了:
instance Monad [] where
m >>= k = foldr ((++) . k) [] m
m >> k = foldr ((++) . (\ _ -> k)) [] m
return x = [x]
fail _ = []
也许不是最明显的定义,但如果你调用>>=
list monad,就会发生这种情况。
概括
所有 monad 共享>>=
和return
和 monad 法则的类型签名。除了这些限制之外,每个 monad 都提供了不同的>>=
and实现return
,如果你想知道所有细节,你必须研究instance Monad ...
声明的源代码。如果您只想学习如何使用特定的 monad,请尝试查找一些相关文档。