3

I'm trying to write a function that will determine if an element exists in a list, both of which being provided by the user. I think a recursive solution is best. This is what I have:

isElement :: a -> [b] -> Bool
isElement a [] = False
isElement a (x:xs) = if a == x then True
                     else isElement a xs

But it can't compile. The error is "Couldn't match expected type -a' with actual type -b'". I don't know what this means or how to fix the problem.

4
  • 2
    Your type signature is wrong. == requires its operands to have the same type, but you have a :: a and x :: b. Commented Sep 18, 2017 at 21:20
  • And not just any type; a needs to be an instance of the Eq type class: isElement :: Eq a => a -> [a] -> Bool. Commented Sep 18, 2017 at 21:34
  • You should always be suspicious when working with True or False near an if. Usually that means the logic could be expressed more directly without an if. In this case, that's true. You could write the body of the second equation as (a == x) || isElement a xs. Commented Sep 19, 2017 at 1:00
  • I guess this question is for the sake of learning, but otherwise elem is a good function to know of. Commented Sep 19, 2017 at 10:35

1 Answer 1

6

You code technically works. It's the type signature that's giving you trouble here.

First, here's the working code:

isElement :: (Eq a) => a -> [a] -> Bool
isElement a [] = False
isElement a (x:xs) = if a == x then True
                     else isElement a xs

I changed two things:

  1. The first thing to keep in mind when working with Haskell's linked lists (the datatype that uses []) is that they can only contain elements of the same type. However in your type signature, a ➞ [b] you specify that you require your first element to be of type a and the ones in your list of type b, different from a.
  2. The second thing is to "enable" equality checks with generic types a and b, and GHC will give you a warning with the steps to follow in order to fix that:

    • No instance for (Eq a) arising from a use of ‘=='
      Possible fix:
        add (Eq a) to the context of
          the type signature for:
            isElement :: a -> [a] -> Bool
    

    So what it tells us is to specify that the a type can be compared!
    And this is fantastic because we can totally do this by giving that clue to the compiler with the (Eq a) => part in our code, that roughly translates to "given this property (Eq) of datatype a, [insert type signature here]". (feel free to correct me here, people of StackOverflow!)

Your code works, and reimplementing functions with this kind of explicit recursion is how I learned how it worked in the first place, so don't hesitate to learn by rewriting the stuff you use, then check their sources on Hackage to see how real-world haskellers actually do it.

Have fun learning!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.