为了进入上下文,我正在将列表理解(从there)转换为“模式过滤”到其monadic对应物(do和bind),然后我遇到异常。
我从这些定义开始(bf为breadthFirst持有),
上下文,数据和帮助
data Tree a = Leaf | Node a (Tree a) (Tree a) deriving Show
let test = Node 1 (Node 2 (Node 4 Leaf Leaf) Leaf) (Node 3 Leaf (Node 5 Leaf Leaf))
let nextChild = concatMap (\x -> case x of; Leaf -> []; Node n l r -> [l,r])
测试功能
let bfLc xs | null xs = [] | otherwise = [ n | Node n _ _ <- xs] ++ (bfLc $ nextChild xs)
let bfDo xs | null xs = [] | otherwise = (do {Node n _ _ <- xs; return n}) ++ (bfDo $ nextChild xs)
let bfBind xs | null xs = [] | otherwise = (xs >>= \(Node n _ _) -> [n]) ++ (bfBind $ nextChild xs)
我做了这些评估,
bfLc [test]
[1,2,3,4,5]
bfDo [test]
[1,2,3,4,5]
bfBind [test]
[1,2,3,4*** Exception: <interactive>:103:53-72: Non-exhaustive patterns in lambda
但我从there
学习do语法为monadic操作链提供了一个简单的简写。 do的基本翻译遵循以下两条规则:
do e1 ; e2 = e1 >> e2 do p <- e1; e2 = e1 >>= \p -> e2
为什么bfBind
失败与bfDo
相反,尽管它们是等价的?
就个人而言,我原本以为他们都失败了,我不知道为什么列表理解或者记谱法成功了? (那么如果你也可以回答这个子问题)
感谢。
答案 0 :(得分:6)
这是因为do
表示法中的失败模式匹配从Monad类调用fail
函数。
特别是,这就是你的表达实际上被贬低的方式:
do {p <- e; stmts} = let ok p = do {stmts}
ok _ = fail "..."
in e >>= ok
此处p
是任何模式,例如您示例中的Node n _ _
。
(请参阅Haskell报告中do expressions部分。)
Monad
的{{1}}实例定义[]
,如下所示:
fail