我关注现实世界的haskell,第2章中有exercise。
我的解决方案是
lastButOne xs = if null xs || null (tail xs)
then []
else if null (tail (tail xs))
then head xs
else lastButOne (tail xs)
但除了[]之外它不起作用,并产生这样的错误。
*Main> lastButOne []
[]
*Main> lastButOne [1, 2]
<interactive>:5:13:
No instance for (Num [a0]) arising from the literal `1'
Possible fix: add an instance declaration for (Num [a0])
In the expression: 1
In the first argument of `lastButOne', namely `[1, 2]'
In the expression: lastButOne [1, 2]
我是一个新手,并不理解这些神秘的错误信息。有任何想法吗?
答案 0 :(得分:7)
这是一个类型问题。如果您使用GHCi,请将此功能加载到其中并使用
:t lastButOne
查看其类型,即
lastButOne :: [[a]] -> [a]
这是因为if
需要在then和else分支上使用相同的类型,并且由于您在[]
分支中返回then
,Haskell认为您正在尝试始终返回一个列表,并且由于您在head xs
分支上返回else
,它认为您正在编写一个函数在列表列表上工作。
但是,[1, 2]
不是列表列表,因此GHC向您大吼大叫关于类型不匹配错误。
另请注意,如果您明确写出类型定义,则无法编译:
lastButOne :: [a] -> a
lastButOne xs = if null xs || null (tail xs)
then []
else if null (tail (tail xs))
then head xs
else lastButOne (tail xs)
GHCi会给你一个错误:
Couldn't match type `a' with `[a0]'
`a' is a rigid type variable bound by
the type signature for lastButOne :: [a] -> a at k.hs:2:1
In the expression: []
In the expression:
if null xs || null (tail xs) then
[]
else
if null (tail (tail xs)) then head xs else lastButOne (tail xs)
In an equation for `lastButOne':
lastButOne xs
= if null xs || null (tail xs) then
[]
else
if null (tail (tail xs)) then head xs else lastButOne (tail xs)
答案 1 :(得分:1)
then []
在这里您返回一个列表。
then head xs
在这里你返回列表中的内容(在你的情况下是一个数字)。我很惊讶这个编译。您应该使用Maybe
包装结果,因此lastButOne []
和lastButOne [x]
的结果应为Nothing
,lastButOne [...,x,_]
的结果应为{{1} }}
或者您可以在错误情况下使用Just x
伪函数。
答案 2 :(得分:1)
我觉得模式匹配对于这个来说更优雅...我自己是Haskell的全新手(很久以前我只是读了一下):
lastButOne ([]) = []
lastButOne (beforeLast:last:[]) = beforeLast
lastButOne (x:xs) = lastButOne xs
我知道这不是对您的错误的解释,但有时最好的解决方案是完全避免这个问题!