与绑定运算符的Haskell模式匹配错误

时间:2015-06-16 20:37:06

标签: haskell pattern-matching bind

我有一项任务,我被困在某个地方,在那里我没有得到任何进一步的帮助。 给定是一个函数:

transpose :: [[a]] -> [[a]]
transpose []       =  []
transpose ([]:ls)  =  transpose ls
transpose ll       =  [h | (h:_) <- ll] : transpose [t |(_:t) <- ll]

我将一方面使用do-notation和另一方面使用bind-operator再次编写它。我可以使用hd,tl和(:)。 我没有使用do-notation解决方案的问题,但是绑定版本存在模式匹配问题。 这是我到目前为止所做的:

transheadA ll = ll >>= \(h:_) ->
    return h

transtailA ll = ll >>= \(_:t) ->
    return t

transposeA :: [[a]] -> [[a]]
transposeA []       =  []
transposeA ([]:ls)  =  transposeA ls
transposeA ll       =  (transheadA ll : transposeA (transtailA ll))

与do-notation相同的样式有效但是使用bind运算符我在transheadA上得到了一个模式匹配错误

\(h:_) -> ...

请参阅:

transposeA [[1,2,3],[4,5,6],[7,8]]
[[1,4,7],[2,5,8],[3,6*** Exception: transpose.hs:(16,22)-(17,24): Non-exhaustive patterns in lambda

我在考虑如何更长时间地解决这个问题,但我不知道,在哪里添加新模式让这个工作。

修改

我当然想要提示。 直接解决方案不是家庭作业和董事会的意义。 谢谢

编辑解决方案

感谢CommuSoft我能解决这个问题。 我现在的解决方案如下:

transheadA :: [[a]] -> [a]
transheadA ll = ll >>= f
    where f (h:_) = return h
          f _     = fail []


transtailA :: [[a]] -> [[a]]
transtailA ll = ll >>= f
    where f (_:t) = return t
          f _     = fail []

transposeA :: [[a]] -> [[a]]
transposeA []       =  []
transposeA ([]:ls)  =  transposeA ls
transposeA ll       =  (transheadA ll : transposeA (transtailA ll))

1 个答案:

答案 0 :(得分:3)

这种方法存在一些问题:

  • transheadA的签名应与transtailA的签名不同。

    transheadA :: [[a]] -> [a]
    transtailA :: [[a]] -> [[a]]
    
  • 由于你在列表推导中做了一些模式匹配,你不能简单地在lambda表达式中使用它:模式可能会失败,在这种情况下,列表推导部分fail也是如此。您可以将其内联为:

    where f (h:_) = return h
          f _ = fail []
    

    然后,您可以在绑定运算符f的一侧使用>>=。显然,这会对如何编码事物产生影响。隐式地为每个这样的模式匹配(因此一切都不是x <-x单个变量)Haskell可以编写这样的fail(注意Haskell不一定使用列表monad)。

  • 正如您可以阅读here列表monad,您不需要使用return,虽然在这种情况下它没有太大的问题,但会减少长度你的代码。在这种情况下,您需要将表达式的右侧替换为[x]而不是x

根据以上提示,我已设法自行修复transpose的实施。我希望这澄清一两件事?