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?
in https://www.haskell.org/tutorial/goodies.html type [a] is defined as followed: [a] is the family of types consisting of, for every type a, the type of lists of a. Lists of integers (e.g. [1,2,3]), lists of characters (['a','b','c']), even lists of lists of integers, etc., are all members of this family.
Haskell has three basic ways to declare a new type: The data declaration, which defines new data types. The type declaration for type synonyms, that is, alternative names for existing types. The newtype declaration, which defines new data types equivalent to existing ones.
A type declaration statement specifies the type, length, and attributes of objects and functions. You can assign initial values to objects. A declaration type specification (declaration_type_spec) is used in a nonexecutable statement.
In a data declaration, a type constructor is the thing on the left hand side of the equals sign. The data constructor(s) are the things on the right hand side of the equals sign. You use type constructors where a type is expected, and you use data constructors where a value is expected.
Yes, you're right, it represents "any type" - the restriction being that all a
s 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With