|
| 1 | +-- # http://learnyouahaskell.com/types-and-typeclasses#typeclasses-101 |
| 2 | + |
| 3 | +-- LOAD THIS FILE WITH ":l typeclasses" within repl (ghci) |
| 4 | +-- and reload with ":r" |
| 5 | + |
| 6 | +-- Typeclasses are like Interfaces that defines some behavior. |
| 7 | +-- If a type is a part of a typeclass, that means that it supports and |
| 8 | +-- implements the behavior the typeclass describes. |
| 9 | + |
| 10 | +-- Lets check type definition of == function/operator. |
| 11 | +-- => :t (==) |
| 12 | +-- ==> (==) :: (Eq a) => a -> a -> Bool |
| 13 | + |
| 14 | +-- Everything before the => symbol is called a class constraint. |
| 15 | +-- So we can read this type definition as; |
| 16 | +-- (==) takes two params of same type and returns a Bool type value, |
| 17 | +-- BUT two params must must be members of the Eq class. |
| 18 | +-- In this case the Eq typeclass provides an interface for testing for equality. |
| 19 | + |
| 20 | +-- All standard Haskell types except for IO and functions are a part of the Eq typeclass. |
| 21 | + |
| 22 | +-- Example; |
| 23 | +-- The elem function has a type of (Eq a) => a -> [a] -> Bool. |
| 24 | +-- Because it uses == operator to check values. |
| 25 | +-- So definition means function will take a type named a, |
| 26 | +-- which implements the behaviors that Eq class describes. |
| 27 | + |
| 28 | +-- We can also see type classes when defining functions without types. |
| 29 | +-- Haskell's type inference will ad Eq for us. |
| 30 | +-- => iseq x y = x == y |
| 31 | +-- => :t iseq |
| 32 | +-- ==> iseq :: Eq a => a -> a -> Bool |
| 33 | + |
| 34 | +-- Some Basic Typeclasses: |
| 35 | + |
| 36 | +-- > Eq |
| 37 | +-- is used for types that support equality testing. |
| 38 | +-- members of it implements == and /= |
| 39 | +-- if a function type definition includes Eq it means function will use == or /= |
| 40 | +-- All the types we mentioned previously except for functions are part of Eq. |
| 41 | + |
| 42 | +-- > Ord |
| 43 | +-- is for types that have an ordering. |
| 44 | +-- covers all the standard comparing functions such as >, <, >= and <= |
| 45 | +-- To be a member of Ord, a type must first be a member of Eq. |
| 46 | +-- All the types we covered so far except for functions are part of Ord. |
| 47 | +-- For example: |
| 48 | +-- compare functions takes two arguments which are members of Ord, |
| 49 | +-- and returns an value of Ordering type. |
| 50 | +-- Ordering is a type that can be GT, LT or EQ, meaning greater than, lesser than and equal. |
| 51 | + |
| 52 | +-- > Show |
| 53 | +-- is for types that can be presented as string. |
| 54 | +-- All the types we covered so far except for functions are part of Show. |
| 55 | +-- Check some functions for example. |
| 56 | + |
| 57 | +-- > Enum |
| 58 | +-- Enum members are sequentially ordered types — they can be enumerated. |
| 59 | +-- We can use them in ranges like; |
| 60 | +-- => ['a'..'e'] |
| 61 | +-- ==> "abcde" |
| 62 | +-- We can get them successors and predecesors because they have defined successors and predecesors; |
| 63 | +-- => succ 1 |
| 64 | +-- ==> 2 |
| 65 | +-- => pred 5 |
| 66 | +-- ==> 4 |
| 67 | +-- Types in this class: (), Bool, Char, Ordering, Int, Integer, Float and Double. |
| 68 | + |
| 69 | +-- > Bounded |
| 70 | +-- Bounded members have an upper and a lower bound. |
| 71 | +-- Like Int, Char, Bool. |
| 72 | +-- We can get bounds with minBound maxBound functions. |
| 73 | +-- => maxBound Bool |
| 74 | +-- ==> True |
| 75 | +-- => minBound Bool |
| 76 | +-- ==> False |
| 77 | +-- All tuples are also part of Bounded if the components are also in it. |
| 78 | + |
| 79 | +-- > Num |
| 80 | +-- Num is a numeric typeclass. Its members have the property of being able to act like numbers. |
| 81 | +-- Wole numbers are also polymorphic constants. They can act like any type that's a member of the Num typeclass. |
| 82 | +-- => :t 20 |
| 83 | +-- ==> (Num t) => t |
| 84 | +-- Int, Integer, Float, Double are types that are in the Num typeclass. |
| 85 | +-- If we examine the type of *, we'll see that it accepts all numbers. |
| 86 | +-- => :t (*) |
| 87 | +-- ==> (*) :: (Num a) => a -> a -> a |
| 88 | +-- To join Num, a type must already be friends with Show and Eq. |
| 89 | + |
| 90 | +-- > Integral |
| 91 | +-- Integral is also a numeric typeclass. |
| 92 | +-- Num includes all numbers, including real numbers and integral numbers, |
| 93 | +-- Integral includes only integral (whole) numbers. In this typeclass are Int and Integer. |
| 94 | + |
| 95 | +-- > Floating |
| 96 | +-- Includes only floating point numbers, so Float and Double. |
| 97 | + |
| 98 | +-- > Read |
| 99 | +-- Takes a string and return a type which is also a member of Read. |
| 100 | +-- Which type of value it should return? |
| 101 | +-- Compiler will told him by infering our usage of value. |
| 102 | +-- For example: |
| 103 | +-- => read "8.2" + "3.8" |
| 104 | +-- ==> 12 |
| 105 | +-- => "True" || False |
| 106 | +-- ==> True |
| 107 | +-- => read "[1,2,3,4]" ++ [3] |
| 108 | +-- ==> [1,2,3,4,3] |
| 109 | +-- => read "1" : [2] |
| 110 | +-- ==> [1,2] |
| 111 | +-- As you can see read returns a type which is "a" (type variable) by knowing what we are doing with that value. |
| 112 | + |
| 113 | +-- Explicit Type Annotations |
| 114 | + |
| 115 | +-- Type annotations are a way of explicitly saying what the type of an expression should be. |
| 116 | +-- We do that by adding :: at the end of the expression and then specifying a type. |
| 117 | +-- For example, when we dont using return value from read, compiler cant know what type it should return. |
| 118 | +-- So we have to explicitly told type. |
| 119 | +-- => read "5" :: Int |
| 120 | +-- ==> 5 |
| 121 | +-- => read "(3, 'a')" :: (Int, Char) |
| 122 | +-- ==> (3, 'a') |
| 123 | + |
| 124 | +-- Multiple Class Constraints |
| 125 | + |
| 126 | +-- It's totaly ok to have multiple Class Constraits. |
| 127 | +-- For example lets examine function fromIntegral. |
| 128 | +-- It takes an integral number and turns it into a more general number. |
| 129 | +-- => :t fromIntegral |
| 130 | +-- ==> fromIntegral :: (Num b, Integral a) => a -> b |
| 131 | +-- So it takes a Integral and returns a Num. |
| 132 | + |
| 133 | +-- Order of constraits is not importanti constraits mean our function will work with that typeclasses. |
| 134 | +-- Lets swap places of fromIntegral constraits: |
| 135 | +fromIntegral' :: (Integral a, Num b) => a -> b |
| 136 | +fromIntegral' n = fromIntegral n |
0 commit comments