0

Still learning Haskell with Get Programming with Haskell.

In the lesson 7 there is the following exercise:

The tail function in Haskell returns an error when called on an empty list. Modify myTail so that it does handle the case of an empty list by returning the empty list.

Where myTail is defined as follows:

myTail (_:xs) = xs

In the very same lesson, we are told that it is possible to check empty lists parameters with pattern matching. Here is an example from the book:

isEmpty [] = True
isEmpty _ = False

So here it is what I thought would do the trick

myTail [] = []
myTail (_:xs) = xs

However, when I use this function with an empty list it throws an exception:

ghci> myTail []
*** Exception: <interactive>:2:1-17: Non-exhaustive patterns in function myTail

What is wrong?

Chris
  • 26,361
  • 5
  • 21
  • 42
pid
  • 181
  • 4
  • I can't reproduce it, are you sure you're running the latest version of the code? – bereal Nov 05 '22 at 18:02
  • `ghci --version` returns `The Glorious Glasgow Haskell Compilation System, version 9.2.4.`. – pid Nov 05 '22 at 18:04
  • I mean, the latest version of your code (i.e. have you re-compiled after the change), not the compiler. – bereal Nov 05 '22 at 18:05
  • 3
    Oh wait, are you running in ghci? IIRC, you can't just define functions with pattern matching in ghci, the next `let myTail` will just create the entire new function (see [this post](https://stackoverflow.com/questions/15733266/pattern-matching-in-ghci)) – bereal Nov 05 '22 at 18:08
  • 6
    You can use `:{` and `:}` in ghci to enter a function/expression on multiple lines. https://stackoverflow.com/questions/2846050/how-to-define-a-function-in-ghci-across-multiple-lines – Chris Nov 05 '22 at 18:10

1 Answers1

2

As it seems you are defining your function entirely within ghci, the most likely source of your problem is that each line is introducing a new myTail function. In this case when you call myTail [] the current myTail function does not handle empty lists, so you get an exception.

ghci> myTail [] = []
ghci> myTail (_:xs) = xs
ghci> myTail []
*** Exception: <interactive>:3:1-18: Non-exhaustive patterns in function myTail

You can define a function across multiple lines using :{ and :}.

ghci> :{
ghci| myTail [] = []
ghci| myTail (_:xs) = xs
ghci| :}
ghci> myTail []
[]

It is worth additionally noting, though, that it doesn't make much sense for a function that returns the tail of a list to return an empty list when given an empty list when in fact an empty list doesn't have a tail.

You may want to use Maybe to handle this possibility.

ghci> :{
ghci| myTail [] = Nothing
ghci| myTail (_:xs) = Just xs
ghci| :}
ghci> :t myTail
myTail :: [a] -> Maybe [a]
ghci> myTail []
Nothing
ghci> myTail [1, 2, 3]
Just [2,3]
Chris
  • 26,361
  • 5
  • 21
  • 42