当我尝试去除它时,为什么我的Haskell符号会中断?

时间:2014-03-28 05:56:06

标签: haskell

我有来自99个Haskell问题的Problem 26的以下代码:

combinations :: Int -> [a] -> [[a]]
combinations 0 _  = return []
combinations n xs = do y:xs' <- tails xs
                       ys <- combinations (n-1) xs'
                       return (y:ys)

上面的代码按预期工作。以下是我的主要功能和打印结果:

main = print $ combinations 2 "abcd"
-- Prints: ["ab","ac","ad","bc","bd","cd"]

作为一项学习练习,我试图"desugar" the do-notation这样:

combinations :: Int -> [a] -> [[a]]
combinations 0 _  = return []
combinations n xs = tails xs >>= \(y:xs') ->
                    do
                        ys <- combinations (n-1) xs'
                        return (y:ys)

这会编译,但在运行时会出现以下错误:

PatternMatchFail: /home/.../test.hs:(46,34)-(49,37): Non-exhaustive patterns in lambda

这里发生了什么?如何使用>>=>>

替换记号

1 个答案:

答案 0 :(得分:15)

来自Haskell Wikibook

  

... lambdas的片段与do块“大致相同”。它不是一个精确的翻译,因为符号添加了模式匹配失败的特殊处理。

考虑这个例子:

f xs = do
       (x:_) <- Just xs
       return x  

g xs = Just xs >>=
       \(x:_) -> return x

对于任何非空列表,这些功能都是相同的。但是f []会返回Nothing,而g []会返回一个与您获得的错误非常相似的错误。

这是因为do符号处理失败的方式不同。 Monad类型类具有fail函数。您正在使用列表monad,它通过返回空列表而失败。 Maybe monad通过返回Nothing来实现它。无论哪种方式,使用此函数处理do表示法中的模式匹配失败,因此存在差异。

所以翻译它的正确方法是:

g xs = Just xs >>= 
       \xs' -> case xs' of
                 (x:_) -> return x
                 []    -> fail "some error"