嵌套 - 如果在Haskell中

kRe*_*oSo 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)
Run Code Online (Sandbox Code Playgroud)

但除了[]之外它不起作用,并产生这样的错误.

*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]
Run Code Online (Sandbox Code Playgroud)

我是一个相当新手,不明白这些神秘的错误信息.有任何想法吗?

zw3*_*324 7

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

:t lastButOne
Run Code Online (Sandbox Code Playgroud)

看它的类型,这是

lastButOne :: [[a]] -> [a]
Run Code Online (Sandbox Code Playgroud)

这是因为if需要在then和else分支上使用相同的类型,并且因为你[]then分支中返回一个,Haskell认为你总是试图返回一个列表,并且因为你head xselse分支上返回,它认为你是编写函数适用于列表列表.

但是,[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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)