5
votes

So I realize this is a possible duplicate question, as there a number of those errors reported on Stack Overflow, but none of the solutions seem to apply to my problem.

So I have the following function:

elementAt' :: Integral b => [a] -> b -> a
elementAt' [x:_] 1 = x
elementAt' [x:xs] y = elementAt' xs yminus1
    where yminus1 = y - 1

In case you're wondering it's problem 3 from 99 Haskell Problems. The goal of the function is to take as input a list and an index, and return the value at that index (starting at 1). I don't want a solution to the problem, if I did I could just look at the ones provided. But I'm getting an error I don't understand. I'm using eclipseFP, the eclipse plugin for haskell and it's underlining the "[x:_]" and "[x:xs]" portions of the function with the following error:

Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for elementAt' :: Integral b => [a] -> b -> a

In all the threads that discuss this error that I've looked at the problem usually occurs when someone tries to give an incorrect output to something which expects a certain type. For example, returning the length of something (which is of type Int) to what should be a "Num a" variable type.

But in my case I'm not even providing a type for variable a. It should be able to be ANYTHING, right? So why am I getting this error? If I understood why I was getting the error I could fix it, but I just don't understand.

Could someone please explain to me why I'm receiving this error?

Your help is much appreciated, thank you. -Asaf

Edit: Every answer provided so far is correct, thank you all for the helpful information. I'm going to pick the one I believe to be most clear (I have to wait 5 minutes to do it though).

4
why not just write elementAt' [x:xs] y = elementAt' xs (y-1) Viktor Mellgren
@Vixen How is that different from what I wrote... other than including a variable declaration? Obviously the compiler would end up doing the exact same thing in either case (correct me if I'm wrong).Asaf
Yes, it's the same, I just think it looks strange to declare something as yminus1, when y-1 reads more easily and looks prettier in my opinionViktor Mellgren

4 Answers

9
votes

Entering your definition without type declaration shows that the inferred type is Integral b => [[a]] -> b -> a. That's correct, your current patterns match lists of lists.

A pattern like

f [pat] = ...

matches a singleton list whose sole element matches pat. You want to work with cons a.k.a. (:) instead of requring a certain length, and then you need parenthesis instead of brackets:

elementAt' (x:xs) n = ...

The error basically says "you treat a (the elements of the first argument) as if it was a list".

3
votes

If you want to matching list to head and tail, you should use

elementAt' (x:_) 1 = x

So, finally

elementAt' :: Integral b => [a] -> b -> a
elementAt' (x:_) 1 = x
elementAt' (x:xs) y = elementAt' xs yminus1
    where yminus1 = y - 1

And

λ> elementAt' [1,2,3] 2
2

Is it what you need?

3
votes

But in my case I'm not even providing a type for variable a. It should be able to be ANYTHING, right?

It has to be able to be anything. According to your type signature the user of your function has to be able to call your function with a being Int, with a being [Char] or with `a´ being whatever else the user wants to.

However the error message is telling you that you defined your function so that it's only possible to call it with a being a list of something. I.e. you defined it, so that the first argument has to be a list of lists - it can't be a list of anything else. And that contradicts your type signature.

1
votes

Use parentheses, not brackets: (x:xs)

module Aaa where

elementAt' (x:_) 1 = x
elementAt' (x:xs) y = elementAt' xs yminus1
    where yminus1 = y - 1