2

I'm getting the following error, if I try to execute my x_length function, that should measure the length of a given list:

Exception: test.hs:2:1-36: Non-exhaustive patterns in function x_length

I load my test.hs file into ghci with Prelude>:l test.hs.

The implementation of the x_length function is (within the test.hs file):

x_length :: [Int] -> Int
x_length (x:xs) = 1 + x_length xs

I've already figured out, that it has to do something with loading the test.hs file, but I haven't figured out, how to solve this issue.

The actual function call I do with x_length [1,2,3,4].

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Habebit
  • 957
  • 6
  • 23
  • 1
    hint: what lists does `(x:xs)` match? If still in doubt, try evaluating your function "by hand" for a reasonably short list, and see what happens – Robin Zigmond May 08 '19 at 09:13
  • 1
    The obvious logical problem with your code is that `x_length` never returns a value. It always calls itself (which calls itself again (which calls itself again (which ...))). – melpomene May 08 '19 at 09:13
  • 4
    What if you reached the *end* of the list, so it is `[]` instead of `(x:xs)`? – Willem Van Onsem May 08 '19 at 09:15
  • @melpomene well it will terminate (assuming a finite list is given), with a runtime exception - exactly the one seen here – Robin Zigmond May 08 '19 at 09:15
  • 4
    @RobinZigmond It's all \_|\_ to me. – melpomene May 08 '19 at 09:16
  • Yes, technically I know that's true. (Almost pointed it out but didn't want to confuse the OP.) But there is an observable difference nonetheless. (I'm honestly not trying to be argumentative though.) – Robin Zigmond May 08 '19 at 09:21
  • 1
    Enabling warnings makes GHC report about the missed `[]` case. I'd recommend to always keep warnings enabled. – chi May 08 '19 at 16:54

1 Answers1

10

Take a look at your definition again:

x_length :: [Int] -> Int
x_length (x:xs) = 1 + x_length xs

Now let's evaluate this for x_length [1,2,3,4]:

x_length [1,2,3,4]
x_length (1:2:3:4:[])
= 1 + x_length (2:3:4:[])
= 1 + 1 + x_length (3:4:[])
= 1 + 1 + 1 + x_length (4:[])
= 1 + 1 + 1 + 1 + x_length []

But your definition doesn't have a case for matching []! It has a case matching (x:xs), but this requires at least one element in the list. Thus the error: 'non-exhaustive patterns'; that is, there was a case which was not matched by a pattern.

To fix this, you'll need one extra case, for x_length []. So your definition will look like this:

x_length :: [Int] -> Int
x_length [] = _something
x_length (x:xs) = 1 + x_length xs

A small exercise for you: what should _something be? (Hint: what is the length of an empty list?) I'll put the answer in spoiler quotes if you need it; hover over it to show the answer.

x_length [] = 0

bradrn
  • 8,337
  • 2
  • 22
  • 51
  • Thank you for your detailed answer. Trough the comment section I've figured out, that I have to check for the empty-list-case. But I didn't know, that I simply could declare a second case `x_length [] = 0` above the actual implementation of the function. Is this method treated as one function or are these two different functions? Sorry, I'm new to Haskell. Thank you very much. – Habebit May 08 '19 at 18:53
  • @TabmanRekoj It's one function, which "branches" into one of multiple definitions depending on which pattern matches the input: the topmost pattern that matches will be used. This can be thought of as being similar to a piecewise function in mathematics. Really though, it's equivalent to using a `case` statement directly inside of the function definition. – DarthFennec May 08 '19 at 20:48
  • @TabmanRekoj To elaborate on DarthFennec's comment: inside the Haskell compiler, `f case1 = _something; f case2 = _somethingelse` is treated _identically_ to `f x = case x of { case1 -> _something; case2 -> _somethingelse }`. – bradrn May 08 '19 at 22:54