Beginner: What does this error mean ? Why isn't my function working?

The error I am getting is

 Variable not in scope: halve :: [a0] -> t

The exercise in 4.8 asks

“Using library functions, define a function halve::[a] → ([a],[a])” that splits an even-lengthed list into two halves. For example

halve [1,2,3,4,5,6]
---should return
([1,2,3], [4,5,6])

Here is what I came up with.

halve :: [a] -> ([a],[a])
halve [] = error "This function does not accept empty lists"
halve xs
    | (length xs) `mod` 2 /= 0 = error "The list does not have an even number of arguments"
    | (take ((length xs) `div` 2) xs , drop ((length xs) `div` 2) xs)

However, I get the above error. that says the variable is not in scope? Why?

I figured out how to get the solution. I’m still confused by the error. I am sure there is a more elegant way of writing this. But here is what I came up with none the less.

halve :: [a] -> ([a],[a])
halve [] = error "This function does not accept empty lists"
halve xs 
    | (length xs) `mod` 2 /= 0 = error "The list does not have an even number of arguments"
    | otherwise = (take ((length xs) `div` 2) xs , drop ((length xs) `div` 2) xs)

I get a parse error on your first example.

Right, after looking at it I figured it was because it was not matching any patterns. That’s why I came up with the otherwise clause.

1 Like

Yes, the reason the first example has a parse error is because the second guard doesn’t have an assignment statement. Taking away all of the details so we can see the structure, what you wrote was

halve [] = foo
halve xs
  | bar = baz
  | qus

And that isn’t legal, you need to have an assignment statement with each of the guards. The parse error says “(possibly incorrect indentation or mismatched brackets)” which is unfortunate because in this case that isn’t exactly what the issue is, the issue is that it was waiting for you to write an = and then something on the right hand side of it, meaning it interpreted everything on the last line as being the left hand side of an assignment statement and never got the = or the right hand side. The issue isn’t really that ‘oh I just needed to put an otherwise clause to cover all cases’, that’s technically correct, but the real issue is that you didn’t have a syntactically valid guard expression because you were missing the full assignment statement. The correct structure needs to look like

halve [] = foo
halve xs
  | bar = baz
  | qix = qus
1 Like

I see. Yeah the otherwise seemed kind of a hacky way to solve it. I updated my solution to .

halve :: [a] -> ([a],[a])
halve [] = error "This function does not accept empty lists"
halve xs 
    | (length xs) `mod` 2 /= 0 = error "The list does not have an even number of arguments"
    | (length xs) `mod` 2 == 0 = (take ((length xs) `div` 2) xs , drop ((length xs) `div` 2) xs)

FYI, if it helps your mental model, here’s the definition of otherwise:

https://hackage.haskell.org/package/base-4.16.0.0/docs/src/GHC.Base.html#otherwise

1 Like

Sorry I don’t think I was perfectly clear, let me try one more time. What I meant by saying the issue wasn’t really about otherwise is that you could have written a function that didn’t have all cases accounted for and it still would have been accepted (you don’t want to do that, but you could). For example

bar a b
  | a < b = 1
  | b < a = 2

This will run. But what happens when you call bar 3 3? It will give a runtime error of "Non-exhaustive patterns in function bar" because you have some patterns that aren’t covered. The function will still run, though. So its not that your error was about needing to use otherwise to have all of the cases covered, it was purely about the syntax, the fact that you didn’t have an assignment statement after the test.

As wyager said, you can think of otherwise as just an alias for True. Haskell checks all of the patterns in order from top to bottom, seeing if the first is True, and if not moving on to the second and so on. Since otherwise will always be True, if it gets to that point the function will always return that case. This is a totally fine thing to do, it is useful and helps cover all cases when it is appropriate. It is true that your rewrite of the function today covers all cases without needing otherwise and that is great! I just want to clarify what I said and stress the point that your issue conceptually had nothing to do with otherwise itself, it had to do with you writing something like

foo x
  | bar = baz
  | qus

which is a syntax error because you need an assignment statement for each guard.

You don’t need to use otherwise, although you definitely can, and you don’t need cover all cases, although you absolutely should. You just need to have the correct syntax or else it won’t work.

3 Likes