嵌套 - 如果在Haskell中

时间:2013-06-06 14:24:08

标签: haskell

我关注现实世界的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]

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

3 个答案:

答案 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]的结果应为NothinglastButOne [...,x,_]的结果应为{{1} }}

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

答案 2 :(得分:1)

我觉得模式匹配对于这个来说更优雅...我自己是Haskell的全新手(很久以前我只是读了一下):

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

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