为什么Haskell中的这个“@”用法不能包含整个列表?
我正在解决 99 个 Haskell 问题并尝试使用这段代码来解决第二个问题,这需要返回数组的倒数第二个元素:
myPen :: [a] -> a
myPen [] = error "Empty lists have no penultimate element."
myPen list@(_:xs)
| length list == 1 = error "Lists size 1 have no penultimate element."
| length xs == 2 = head xs
| otherwise = myPen xs
这段代码可以编译,但是当给出输入时
myPen [1,2]
它产生错误
*** Exception: Lists size 1 have no penultimate element.
CallStack (from HasCallStack):
error, called at prob1_10.hs:16:25 in main:Main
据我所知,@在这种情况下应该允许引用整个列表,但它似乎只引用xs了列表的或尾部。
这似乎支持了它应该同时包含x和的论点xs。
我的问题有两个:
1.) 这是为什么?2.) 引用整个列表的正确方法是什么?
回答
在这种情况下发生的情况实际上是length list == 2, but length xs == 1,因此第一个或第二个守卫都不会匹配。该otherwise防护件将采取并调用该函数递归上xs,其具有长度为1,以便在第一防护件将采取以及将被打印的错误信息。你可以通过写来修复它:
myPen :: [a] -> a
myPen [] = error "Empty lists have no penultimate element."
myPen list@(_:xs)
| length list == 1 = error "Lists size 1 have no penultimate element."
| length list == 2 = head list
| otherwise = myPen xs
但是在 Haskell 中,使用模式匹配而不是length函数来执行此操作通常更常见,如下所示:
myPen :: [a] -> a
myPen [] = error "Empty lists have no penultimate element."
myPen [_] = error "Lists size 1 have no penultimate element."
myPen [x,_] = x
myPen (_:xs) = myPen xs