1

我遵循现实世界的haskell,第2章有一个练习

我的解决方案是

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]

我是一个新手,不理解神秘的错误消息。有任何想法吗?

4

3 回答 3

7

这是一个类型问题。如果您使用 GHCi,请将此功能加载到其中并使用

:t lastButOne

查看它的类型,即

lastButOne :: [[a]] -> [a]

这是因为if需要在 then 和 else 分支上具有相同的类型,并且由于您[]then分支中返回 a ,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)
于 2013-06-06T14:29:33.163 回答
1

then []在这里你返回一个列表。

then head xs在这里,您返回列表中的内容(在您的情况下为数字)。我很惊讶这个编译。你应该用 a 包裹结果Maybe,所以and 的结果应该是,而lastButOne []应该是的结果。lastButOne [x]NothinglastButOne [...,x,_]Just x

或者您可以error在错误情况下使用伪函数。

于 2013-06-06T14:29:40.937 回答
1

我认为模式匹配对此更优雅......作为Haskell的新手(我很久以前刚刚读过一点):

lastButOne ([]) = []
lastButOne (beforeLast:last:[]) = beforeLast
lastButOne (x:xs) = lastButOne xs

我知道这不是对您的错误的解释,但有时最好的解决方案是完全避免该问题!

于 2013-06-06T14:34:57.900 回答