trujello
trujello

Reputation: 145

Haskell type signatures: Question on type signature of lastButOne Program

I'm reading through Real World Haskell and one of the exercises is to construct a function lastButOne, which simply returns the second to last element of a list.

My code so far:

lastButOne xs = if null xs || length xs == 1
                    then []
                else if length xs == 2
                    then head xs
                else lastButOne (tail xs)

My problem: The input should be a list, which then returns an empty list if it is either nonempty or is of length 1, and in other cases returns the second to last element. However, I get an error when I input a list. I don't get any errors when I input a second order nested list.

I suspected something was wrong with the type signature, and when I call the type signature, it returns

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

But I want the type signature to be [a] -> a. I've stared at this function for a while and have explored other posts, but I can't seem to figure out why the type signature is [[a]] -> a. Any hints would be appreciated.

Upvotes: 2

Views: 97

Answers (2)

developer_hatch
developer_hatch

Reputation: 16224

You can acomplish that with pattern matching like:

lastButOne :: [a] -> a
lastButOne []    = error "not elements"
lastButOne [x]   = x
lastButOne [x,_] = x
lastButOne (x:xs) = lastButOne xs

Upvotes: 5

lzbernardo
lzbernardo

Reputation: 196

You may explicitly declare your function's type signature by adding lastButOne :: [a] -> [a] to your code. The function will then expect xs to be a list.

But then we would meet another error: the fact that one of the outputs of your function (head xs) isn't in fact a list [a], but rather an element a.

A similar error message will pop up if you add the signature lastButOne :: [a] -> a, but this time because [] is not an element of type a.

A simple solution might be to return your second to last element inside a list, using [head xs] as an output.

Upvotes: 1

Related Questions