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

Haskell pattern match error with bind operator

我有一个任务,我被困在一个点上,我无法继续前进。 给出的是一个函数:

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 的相同样式有效,但使用绑定运算符时,我在 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))

这种方法存在一些问题:

  • 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 for the list monad,你不需要使用 return,虽然在这种情况下它不是什么大问题,但是会减少代码的长度。在这种情况下,您需要将表达式的右侧替换为 [x] 而不是 x.

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