ADW
ADW

Reputation: 15

My function return last list has an error

I just started learning Haskell, and I intended to code a function that would return to last list 2.

lastButOne x = if ((==) (length x) 2)
               then (head x)
               else (tail x)

this is error:

    ‧ Occurs check: cannot construct the infinite type: a ~ [a]
    ‧ In the expression: (tail x)
      In the expression:
        if ((==) (length x) 2) then (head x) else (tail x)
      In an equation for ‘lastButOne’:
          lastButOne x = if ((==) (length x) 2) then (head x) else (tail x)
    ‧ Relevant bindings include
        x :: [a] (bound at D:\\tool\8.6.3\test\lBoErr.hs:1:12)
        lastButOne :: [a] -> a (bound at D:\\tool\8.6.3\test\lBoErr.hs:1:1)

  |
3 |                            else (tail x)
  |                                  ^^^^^^

I do not understand where my code is wrong and what the error meant.

Upvotes: 1

Views: 52

Answers (1)

chepner
chepner

Reputation: 532063

lastButOne has intended type [a] -> a, but with tail x you are trying to return a value of type [a]. The error message results from the type checker's attempt to find a type which unifies with both a and [a], in an attempt to make sense of a function that returns one or the other depending on which branch is taken.

What you want to do is recurse on the tail of the list:

lastButOne x = if length x == 2
               then head x
               else lastButOne (tail x)

This is more naturally written using pattern matching, though.

lastButOne [x,_] = x  -- lists of length exactly 2
lastButOne (_:xs) = lastButOne xs -- All other non-empty lists

Note lastButOne simply is not defined for empty or singleton lists, and will produce a run-time error if called on such. You can fix that by altering the return to Maybe a:

lastButOne :: [a] -> Maybe a
lastButOne [x,_] = Just x
lastButOne (_:xs) = lastButOne xs
lastButOne _ = Nothing

Upvotes: 4

Related Questions