A typeclass is a sort of interface which defines a behaviour. They are kind of like interfaces in Java in the sense if a type is a part of a typeclass it must implement the behaviour the typeclass specifies.
For example, what is type signature of
λ: :t (==) (==) :: Eq a => a -> a -> Bool
The part between
=> is the class constraint. Here it specifies that there is only one type supported for this operation parameters (
a) and that type must be part of the typeclass
λ: :t (>=) (>=) :: Ord a => a -> a -> Bool
Here, it is specifying that the input params must be of same type and they must implement the typeclass
elem function has the type:
λ: :t elem elem :: (Foldable t, Eq a) => a -> t a -> Bool
Here the type of the element and the element array individual element must be same and that type should implement
For example this won’t work:
elem 'dog' [1, 2, 3].
Eq used for types that support equality testing. They implement:
λ: 5 == 5 True λ: 4 == 5 False λ: 4 /= 5 True λ: 4 /= 4 False
Ord used for types that support ordering. They implement
compare function takes two
Ord values and returns an enum:
λ: :t compare compare :: Ord a => a -> a -> Ordering λ: compare 2 2 EQ λ: compare 2 1 GT λ: compare 2 3 LT λ: LT LT
Show and Read
Show members can be presented as strings. It’s equivalent to the method
toString in Java and
__str__ in python. They implement the
λ: show 3 "3" λ: show "Cat" "\"Cat\"" λ: show 'c' "'c'" λ: show True "True"
Read is sort of the opposite typeclass of Show. The read function takes a string and returns a type which is a member of Read. They implement the
λ: read "8" :: Int 8 λ: read "8.2" :: Float 8.2 λ: read "True" :: Bool True
read method needs an inference type to figure out the type of the result. Without that it won’t be able to figure out to which type’s read method would be call. That is done by
Enum members are sequentially ordered types with names. We can use them in ranges (as they are ordered). They implement the
λ: ['a'..'e'] "abcde" λ: [LT .. GT] [LT,EQ,GT] λ: [3 .. 5] [3,4,5] λ: succ 'q' 'r' λ: pred 43 42
Bounded members have a upper and a lower bound. They implement the
λ: minBound :: Int -9223372036854775808 λ: minBound :: Char '\NUL' λ: minBound :: Bool False λ: maxBound :: Bool True λ: maxBound :: Char '\1114111' λ: maxBound :: Int 9223372036854775807
Num is a numeric typeclass. Its members basically have to behave like well…a number.
Numeric literals practically act like polymorphic constants. They can act like any type that’s a member of the
λ: 20 :: Int 20 λ: 20 :: Integer 20 λ: 20 :: Float 20.0 λ: 20 :: Double 20.0
Num the type must satisfy both
Eq as well as a glut of other operations.
λ: :t (+) (+) :: Num a => a -> a -> a λ: :t (-) (-) :: Num a => a -> a -> a λ: :t (*) (*) :: Num a => a -> a -> a
Integralis also a numeric typeclass.
Numincludes all numbers, including reals and integral numbers, Integral includes only integral (whole) numbers. In this typeclass are Int and Integer.
Floatingincludes only floating point numbers, so Float and Double.
Fractionalis any kind of number for which we can define a division. It’s a superset of
mod are fractional, integral respectively and
^ only supports an integral power.
λ: :t (/) (/) :: Fractional a => a -> a -> a λ: :t (mod) (mod) :: Integral a => a -> a -> a λ: :t (^) (^) :: (Integral b, Num a) => a -> b -> a
A very useful function for dealing with numbers is
fromIntegral :: (Integral a, Num b) => a -> b
It takes an integral number and converts it into a more generic number to perform operations such that it works nicely with floating point numbers.