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

But*_*840 13 haskell

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

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

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

main = print $ combinations 2 "abcd"
-- Prints: ["ab","ac","ad","bc","bd","cd"]
Run Code Online (Sandbox Code Playgroud)

作为一个学习练习,我试图"desugar"这样的记号:

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

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

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

这里发生了什么?如何用>>=和替换do-notation >>

Ben*_*esh 15

来自Haskell Wikibook:

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

考虑这个例子:

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

g xs = Just xs >>=
       \(x:_) -> return x
Run Code Online (Sandbox Code Playgroud)

对于任何非空列表,这些功能都是相同的.但f []返回Nothing,并g []返回一个错误,就像你得到的错误.

这是因为do符号处理失败的方式不同.该Monad类型类具有fail的功能.您正在使用列表monad,它通过返回空列表而失败.该Maybe单子通过返回实现它Nothing.无论哪种方式,do符号内的模式匹配失败都是用这个函数处理的,因此存在差异.

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

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

  • @ Buttons840它只是一个方便,只是比你想象的多一点. (3认同)
  • @ Buttons840它_is_句法糖.如果没有这种记谱法,它就不会做任何魔法. (2认同)