Zulaxs
Zulaxs

Reputation: 11

Checking whether element is in list or not

I have just started writing my first few programs in Haskell and I'm struggling a lot - so please excuse errors galore. I found this practice problem online and it wants me to take in a list, an int, and return a bool. I should check if the int is to be found within the list or not and return true or false, respectively. This is what I have:

import Data.List

elem':: (Eq a) => a -> [a] -> Bool
   elem' x [x] 
      | x == [x:xs] = True
      | length [x] == 1 = False
      | otherwise = elem' tail [x]

The compiler returns

Illegal type signature [...] Type signatures are only allowed in patterns with ScopedTypeVariables

which I cannot really make sense of yet. I've found some people saying that this error occurs when using tabs instead of spaces, yet I solely used spaces. I am grateful for any advice!

Upvotes: 0

Views: 976

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120711

First you have a simple indentation problem. Your definition is parsed as

elem':: (Eq a) => a -> [a] -> Bool elem' x [x] 
      | x == [x:xs] = True
      | length [x] == 1 = False
      | otherwise = elem' tail [x]

I'm a bit surprised that this isn't reported as a parse error, but basically it is one.

What you need to do is, indent all function clauses to the same level as the signature (i.e. in this case, not indented at all).

elem':: (Eq a) => a -> [a] -> Bool
elem' x [x] 
 | x == [x:xs] = True
 | length [x] == 1 = False
 | otherwise = elem' tail [x]

This is still very wrong though. First, you're matching twice on x. This is not possible in Haskell. OTOH there's no variable xs in scope. If it were, it would have to have type [a], and then [x:xs] would have type [[a]]: a nested list. But then comparing it to x, which is not even a simple list, doesn't make any sense. length [x] is always 1, regardless of what x is. Similarly, tail [x] is always the empty list (but that's not even what's used here, you've actually wrote that the tail function should be passed as an argument to elem').

Perhaps the confusion comes from the fact that [ ] can mean two different things: one the type level, it means you're talking about lists of elements of the enclosed type. I.e. [a] is the type of lists whose elements have type a.
By contrast, on the value level, [x] is specifically the list that contains only a single element, namely x.

You should make sure you understand how pattern matching works. Your clause would have been legal if you had two different variables in it. Then, matching [y] would mean this clause only accepts lists with exactly one element, and y will than be the value of the single element. In this case, the correct implementation would be

elem' x [y] = x==y

(Alternatively, you could have guards here yielding True and False, but that's just redundant work.)

Actually though there's no good reason to have a clause for exactly one element. All you need is a clause for zero elements

elem' x [] = ...

and a clause for at least one element:

elem' x (y:ys)
 | ...
 | ...

Upvotes: 3

Related Questions