Types
Type Variables (Generics)
Haskell’s version of generics are called Type Variables.
head :: [a] -> a
Functions that use type variables are called polymorphic functions.
Type variables are usually named in the format a
, b
, c
, d
… etc.
Typesclasses
Typeclasses are similar interfaces in object oriented languages or traits in Rust, they are used to describe a behavior that a type implements.
Below is an example of the ==
equality operator’s type signature. The =>
hash rocket is used to show the type classes of different inputs to a function, these are also called class constraints. In the case of ==
, this type signature shows that the type a
must implement the class constraint Eq
to passed into this function.
== :: (Eq a) => a -> a -> Bool
The Ord
typeclass takes types that can be ordered in a hierarchy. Types can only be part of Ord
if they also implement Eq
.
The Show
typeclass describes types that can be presented as strings.
The Read
typeclass describes types that can coerced from a string form into their actual type. This can be demonstrated using the read
function
read "8" - 3
-- 5
read "True" || False
-- True
In the examples above the type that read
outputs is inferred by how it is used. However, if you use read
on its own without usage then the type returned is ambiguous and the compiler will complain with ambiguous type variable
. You can resolve ambiguous types by including a type annotation after the use of the function.
read "5" :: Int
-- 5
read "5" :: Float
-- 5.0
The Enum
typeclass can be sequentially ordered and enumerated. This includes types that can be placed in ranges. Such as Char
and Int
.
The Bounded
has members that have an upper and a lower bound. You can get these bounds by using the minBound
and maxBound
functions.
minBound :: Int
-- -2147483648
maxBound :: Char
-- '\1114111'
The Num
typeclass has members that behave like numbers. Whole numbers act like polymorphic constants because they can stand in for many types that are members of the Num
typeclass.
20 :: Int
-- 20
20 :: Float
-- 20.0
20 :: Double
-- 20.0
Operators that use Num
only work with the same type, however, often haskell can automatically resolve these types to be the same however if you use explicit type annotations you can short circuit this behavior.
(5 :: Int) * (6 :: Integer)
-- ERROR
You can convert integral numbers to more general numbers using the fromIntegral
function. This takes a number that is a member of the Integral
typeclass and returns a member of the Num
typeclass.
fromIntegral :: (Num b, Integral a) => a -> b
formInrtegral (length [1, 2, 3, 4]) + 3.2
-- 7.2