Chap 3 | Types and Typeclasses
Believe the type
We can get a type of expressions with :t
command in GHCi.
ghci> :t 'a' 'a' :: Char
::
is read as "has type of". In the example above, Haskell says "'a'
has type of Char
". Explicit types are always denoted with the first letter in capital case, for example, Char
, Bool
, or Int
. Square brackets in type name denote a list. [Char]
is read as "a list of characters" or "a string". Each tuple has its own type. (Bool, Char)
is different from (Char, Char, Char)
.
Functions also have types. We can optionally give functions an explicit type declaration when defining ones. This is generally considered to be a good practice.
removeNonUppercase :: [Char] -> [Char] removeNonUppercase st = [c | c <- st, c `elem` ['A'..'Z']]
removeNonUppercase
has type of [Char] -> [Char]
, meaning that it maps from a String
to a String
. In fact, String
is a synonym for [Char]
so we can also write the previous example as below.
removeNonUpperCase :: String -> String
For a function that takes several parameters, we do as below.
addThreeInts :: Int -> Int -> Int -> Int addThreeInts x y z = x + y + z
It takes three Int
s, adds them up, and returns the result. There is no explicit distinction between parameters and a return value in a function declaration. They are just separated by ->
. Simply the last item in the ->
chain is the return value's type.
An overview of some common types
Int
is an N-bit signed integer on N-bit machines. On a 64-bit system,Int
is bounded inside [-9223372036854775808, 9223372036854775807].Integer
is also an integer except that it isn't bounded in any range.Float
is a single precision floating point number.Double
is a double precision floating point number.Bool
is a boolean. The only two variants areTrue
orFalse
.Char
is a character. It's denoted by single quotes. A list ofChar
is aString
.
Type variables
The built-in function head
has type of [a] -> a
.
ghci> :t head head :: [a] -> a
Here, a
is a type variable. It isn't a type. (Remember, explicit types are written capital-cased) A type variable describes that it can be of any type. This is like generics in other languages. Functions that have type variables in their declaration are called polymorphic functions. head
is polymorphic. It takes a list of any type and returns an element of that type.
Typeclasses 101
Typeclasses are like interfaces in other languages. If a type is a member of a typeclass, the type supports and implements the behavior the typeclass specifies.
In Haskell, ==
is an infix function and it has type. (Infix functions have to be surrounded by parenthesis when they are not placed between operands)
ghci> :t (==) (==) :: Eq a => a -> a -> Bool -- +-------+------+ +----+ -- |Typeclass | -- |Parameters -- |Return value
Eq a =>
is a new thing here. A thing placed before =>
is called a class constraint. The previous declaration means that the ==
function takes exactly two parameters that are of the same type and returns a value of type Bool
. Besides, the two parameters have to be a member of the typeclass Eq
. Equivalence has to be defined among the parameter candidates.
Some basic typeclasses
Eq
is for types that support equality testing. Its members have to implement==
and/=
.Ord
is for types that have an ordering. Its members have to implement>
,<
,>=
, and<=
.Show
is for types that can be shown to a human. One of the most important functions a value whose type is a member ofShow
implements isshow
.Read
is sort of the opposite typeclass ofShow
. The built-inread
function takes aString
value and returns a value whose type is a part ofRead
typeclass.Enum
members are sequentially ordered types. Values that implementsEnum
have successors and predecessors, which you can get withsucc
andpred
respectively. Types in this typeclass are()
,Bool
,Char
,Ordering
,Int
,Integer
,Float
, andDouble
.Bounded
members have an upper and a lower bound. Built-in functionminBound
andmaxBound
have type ofBounded a => a
. They take no parameter. They're, so to speak, polymorphic constants. Tuples are bounded if their members are all bounded.Num
is a numeric typeclass. For example, a literal20
's type isNum p => p
so it is also a polymorphic constant.Int
,Integer
,Float
, andDouble
are member ofNum
typeclass.Integral
is also a numeric typeclass but it only includesInt
andInteger
.Floating
is also a numeric typeclass but it only includesFloat
andDouble
.