5
votes

This is perhaps a very basic question, but, nevertheless, it does not seem to have been covered on SO.

I recently took up Haskell and up until now type declarations consisted of mostly the following:

Int
Bool
Float
etc, etc

Now I am getting into lists and I am seeing type declarations that use a, such as in the following function that iterates through an associative list:

contains :: Int -> [(Int,a)] -> [a]
contains x list = [values | (key,values)<-list, x==key]

Can someone provide an explanation as to what this a is, and how it works? From observation it seems to represent every type. Does this mean I can input any list of any type as parameter?

2

2 Answers

12
votes

Yes, you're right, it represents "any type" - the restriction being that all as in a given type signature must resolve to the same type. So you can input a list of any type, but when you use contains to look up a value in the list, the value you look up must be the same type as the elements of the list - which makes sense of course.

1
votes

In Haskell, uppercase types are concrete types (Int, Bool) or type constructors (Maybe, Either) while lowercase types are type variables. A function is implicitly generic in all the type variables it uses, so this:

contains :: Int -> [(Int, a)] -> [a]

Is shorthand for this*:

contains :: forall a. Int -> [(Int, a)] -> [a]

In C++, forall is spelled template:

template<typename a>
list<a> contains(int, list<pair<int, a>>);

In Java and C#, it’s spelled with angle brackets:

list<a> contains<a>(int, list<pair<int, a>>);

Of course, in these languages, generic type variables are often called T, U, V, while in Haskell they’re often called a, b, c. It’s just a difference of convention.

* This syntax is enabled by the -XExplicitForAll flag in GHC, as well as other extensions.