99 Haskell Problems - Problem 2 Background

This is my first experience with functional programming and totally self-study. I just have 2-3 days' worth experience in Haskell. Now let's continue with actual code.



For Problem 2 of 99 haskell problems I wrote this function

module Functions 
(
lastButOne
) where

lastButOne :: [a] -&gt; a
lastButOne [a, b] = a
lastButOne (_:xs) = lastButOne xs
lastButOne a = error "Not Supported"


Is this code ok from functional programming perspective? I am open to criticism from any perspective. 

EDIT 1

Code after @Pedro Rodrigues suggestions

lastButOne :: [a] -&gt; a
lastButOne [a, _] = a
lastButOne (_:xs) = lastButOne xs
lastButOne _ = error "lastButOne requires a list with at least 2 members"
You have the right idea, I just want to make a few remarks:


You could have used _ in the first and the last clause of your function in place of the ignored arguments. It might help readability to know right away that an argument is being ignored.
You're explicitly throwing an error on invalid input which is fine. A good error message could be more helpful to the caller than just getting a pattern match fail. However it wouldn't have shocked me if you had omitted that last line. An even safer solution is having the function return Just a when the input is valid and Nothing when it's not, but for performance/convenience's sake many partial functions out there don't do that.


EDIT: To elaborate more on the safer solution point I mentioned earlier: lastButOne has type lastButOne :: [a] -&gt; a. However this type fails to convey that lastButOne is a partial function, and therefore may fail on certain inputs. It's very easy for a caller to overlook that he needs to watch out for invalid inputs. However, had you defined lastButOne as lastButOne :: [a] -&gt; Maybe a instead, then the fact that it might not produce a result for some inputs, is directly encoded in the type of the function, thus making it type safer. Any caller of lastButOne couldn't possibly overlook that he needs to handle failure.

In case you haven't heard of Maybe yet, it's a data structure that is used to elegantly express a computation that may fail. Examples:

my_div :: Integer -&gt; Integer -&gt; Maybe Integer
my_div _ 0 = Nothing
my_div a b = Just (div a b)


lastButOne :: [a] -&gt; Maybe a
lastButOne [a, _] = Just a
lastButOne (_:xs) = lastButOne xs
lastButOne _ = Nothing