2018-11-21 10:06

Page 1
- Many programming languages have some form of overloading.
- Often limited to built-in operators:
- Equality tests for all basic types.
- Numeric operators for integers and floating point numbers.

- In some languages you can define your own overloaded functions:
- Just define two or more functions with the same name, but different types.

- Haskell takes this a step further…

`:t (*)`

(*) :: Num a => a -> a -> a`square x = x * x`

`:t square`

square :: Num a => a -> a- The new function "inherits" the overloading of the operator…
- The function will work on
`square`*any*type in theclass, even types that haven't been defined yet!**Num** - As a more illustrative example, consider
`sort`**::****Ord**`a`**=>**[`a`]**->**[`a`]

- that "inherts" the overloading of the operator…
`<=`

- A
*type class*declares a set of*methods*, i.e. a set of related overloaded functions and operators. - Here is the definition of the predefined class:
**Num****class****Num**`a`**where**(`+`), (`*`), (`-`)**::**`a`**->**`a`**->**`a``negate`,`abs`,`signum`**::**`a`**->**`a``fromInteger`**::****Integer****->**`a`

- An
*instance declaration*provides implementations of methods for a specific type:**instance****Num****Int****where**-- ...**instance****Num****Integer****where**-- ...**instance****Num****Double****where**-- ...**instance****Num****Float****where**-- ...

- Note: in spite of the similar terminology, type classes in Haskell are for overloading, not for objects, like in object oriented languages.

**class****Eq**`a`**where**(`==`), (`/=`)**::**`a`**->**`a`**->****Bool**`a``/=``b`**=**`not`(`a``==``b`) -- default implementation`a``==``b`**=**`not`(`a``/=``b`) -- default implementation**instance****Eq****Int****where**-- ...**instance****Eq****Double****where**-- ...**instance****Eq****Char****where**-- ... -- There are instances for almost all predefined types- Quiz: which types do
*not*support equality tests?

- Example of how to define an instance of class
**Eq**(

`==`)**Red****Yellow****Green****Red****True****False****False****Yellow****False****True****False****Green****False****False****True** **data****TrafficLight****=****Red****|****Yellow****|****Green****instance****Eq****TrafficLight****where****Red**`==`**Red****=****True****Yellow**`==`**Yellow****=****True****Green**`==`**Green****=****True****_**`==`**_****=****False**- (the above instance is what you get when you use

)**deriving****Eq**

- (the above instance is what you get when you use

**instance**(**Eq**`a`,**Eq**`b`)**=>****Eq**(`a`,`b`)**where**(`x1`,`y1`)`==`(`x2`,`y2`)**=**`x1``==``x2``&&``y1``==``y2`- Pairs can be tested for equality if both parts can be tested for equality.
- Similarly for larger tuples.
- Note: this definition
*is not*recursive.

**instance****Eq**`a`**=>****Eq**[`a`]**where**[]`==`[]**=****True**`x`**:**`xs``==``y`**:**`ys`**=**`x``==``y``&&``xs``==``ys`**_**`==`**_****=****False**- List can be tested for equality if the elements can be tested for equality
- Note: this definition
*is*recursive.

- Take another look at these instance declarations
**instance**(**Eq**`a`,**Eq**`b`)**=>****Eq**(`a`,`b`)**where**-- ...**instance****Eq**`a`**=>****Eq**[`a`]**where**-- ...- They are rules that can be applied repeatedly,
to generate instances for arbitrarily complex types.
- Base cases: ,
**Eq****Int**,**Eq****Bool**, …**Eq****Char** - Applying the rules:
- ,
**Eq****String**,**Eq**[**Int**],**Eq**[[**Int**]], …**Eq**[[[**Int**]]] - ,
**Eq**(**Int**,**Bool**),**Eq**[(**Int**,**Bool**)], …**Eq**([**Int**],[**Bool**]) - …

- Type classes can be seen as a simple automatic programming system: the programmer picks the type, the instances generate the code.

- Base cases:

**class****Eq**`a`**=>****Ord**`a`**where**(`<`), (`<=`), (`>`), (`>=`)**::**`a`**->**`a`**->****Bool**`compare`**::**`a`**->**`a`**->****Ordering**`max`,`min`**::**`a`**->**`a`**->**`a`**data****Ordering****=****LT****|****EQ****|****GT**- There are instances for almost all predefined types.
- is a
**Ord***subclass*of.**Eq**- All types that are in the class are also in the
**Ord**class.**Eq** - It is expected that when returns
`x``==``y`, then**True**returns`compare``x``y`.**EQ**

- All types that are in the

**class****Enum**`a`**where**`pred`,`succ`**::**`a`**->**`a``toEnum`**::****Int****->**`a``fromEnum`**::**`a`**->****Int**`enumFrom`**::**`a`**->**[`a`]`enumFromTo`**::**`a`**->**`a`**->**[`a`] -- ...- It's enough to define and
`fromEnum`, the other methods have default implementations.`toEnum` - Instances: ,
**Bool**,**Int**,**Integer**,**Float**, …**Double**

Enum

[1

**..**5]`==`[1,2,3,4,5][1

**..**]`==`[1,2,3,4,5,`…`]['a'

**..**'g']`==`"abcdefg"- -- watch out for rounding errors…
[0.5

**..**3]`==`[0.5,1.5,2.5,3.5] - This is syntactic sugar for the methods of the class:
**Enum**[

`x`**..**`y`]`==``enumFromTo``x``y`[

`x`**..**]`==``enumFrom``x`

**class****Bounded**`a`**where**`minBound`,`maxBound`**::**`a`- Instances: ,
**Bool**,**Char**, tuples**Int** - Not bounded:
**Integer** - Example:
`enumAll`**::**(**Bounded**`a`,**Enum**`a`)**=>**[`a`]`enumAll`**=**[`minBound`**..**`maxBound`]

**class****Show**`a`**where**`show`**::**`a`**->****String**-- some more functions...**class****Read**`a`**where**`read`**::****String****->**`a`-- some more functions...- There are instances for almost all predefined types.
- Note that for , which instance is used depends
`read`*not*on the type of the argument, but on how the result is used.- Overloading is
*resolved*by the type checker.

- Overloading is

- For many predefined classes, in particular ,
**Eq**,**Ord**,**Show**,**Read**and**Enum**, there is a standard way to define instances.**Bounded** - The Haskell compiler knows how to define these instances.
- So, when you define a new data type, you can get instances for free!
**data****Suit****=****Spades****|****Hearts****|****Diamonds****|****Clubs****deriving**(**Eq**,**Ord**,**Show**,**Read**,**Enum**,**Bounded**)

dataSuit=Spades|Hearts|Diamonds|Clubsderiving(Eq,Ord,Enum,Bounded)instanceShowSuitwhereshowSpades="♠"showHearts="♥"showDiamonds="♦"showClubs="♣"

dataRank=NumericInt|Jack|Queen|King|Acederiving(Eq,Ord)instanceShowRankwhereshow(Numericn)=shownshowJack="J"showQueen="Q"showKing="K"showAce="A"

**data****Card****=****Card**{`rank`**::****Rank**,`suit`**::****Suit**}**instance****Show****Card****where**`show`(**Card**`r``s`)**=**`show``r``++``show``s`- Quiz: is this a recursive definition?

**data****Hand****=****Empty****|****Add****Card****Hand****instance****Show****Hand****where**`show`**Empty****=**"."`show`(**Add**`c``h`)**=**`show``c``++`" "`++``show``h`- Quiz: is this a recursive definition?

- With

:**deriving****Show**`example_hand_2`

Add (Card {rank = Ace, suit = Spades}) (Add (Card {rank = King, suit = Clubs}) Empty)

- With the hand-written instances:
**Show**`example_hand_2`

A♠ K♣

**class****Functor**`f`**where**`fmap`**::**(`a`**->**`b`)**->**`f``a`**->**`f``b``f``<$>``d`**=**`fmap``f``d`- A generalisation of to other types with one parameter.
`map``map`**::**(`a`**->**`b`)**->**[`a`]**->**[`b`]`fmap`**::****Functor**`f`**=>**(`a`**->**`b`)**->**`f``a`**->**`f``b`

- Instances: ,
[]

,**Maybe**, …**IO**

is supported as an extension in GHC.**deriving****Functor**- Put
`{-# LANGUAGE DeriveFunctor #-}`

in the beginning of your module to enable this extension.

- Put

**class****Foldable**`t`**where**`foldr`**::**(`a`**->**`b`**->**`b`)**->**`b`**->**`t``a`**->**`b`-- ...- A generalisation of from lists to other types with one parameter.
`foldr` - Instances: ,
[]

, …**Maybe** - This class is included in the Prelude in recent versions of GHC, but not in the official Haskell language definition.

is supported as an extension in GHC.**deriving****Foldable**- Put
`{-# LANGUAGE DeriveFoldable #-}`

in the beginning of your module to enable this extension

- Put

- A class to enumerate all the values of "small" types.
**class****Small**`a`**where**`values`**::**[`a`]

- Some instances:
**instance****Small****Bool****where**`values`**=**[**False**,**True**]**instance****Small****Suit****where**`values`**=**[`maxBound`**..**`minBound`]**instance****Small****Rank****where**`values`**=**(`...`)**instance****Small****Card****where**`values`**=**[**Card**`r``s`**|**`s`**<-**`values`,`r`**<-**`values`]

- Testing if a property holds for all values
`smallCheck`**::****Small**`a`**=>**(`a`**->****Bool**)**->****Bool**`smallCheck``p`**=**`and`[`p``x`**|**`x`**<-**`values`]

- Exhaustive testing!
- Better than random testing!
- Unfortunately it's only practical when the argument types are sufficiently small…

- As defined above, can only test properties with
`smallCheck`*one*argument. What if we want it to work for an arbitrary number of arguments, like?`quickCheck`

classSmallCheckpropwheresmallCheck::prop->BoolinstanceSmallCheckBoolwheresmallCheckb=binstance(Smalla,SmallCheckprop)=>SmallCheck(a->prop)wheresmallCheckf=and[smallCheck(fx)|x<-values]

- Consider
`f`**::****String****->****String**`f``s`**=**`show`(`read``s`)

- Will this work? Compare with
`square`**::****Num**`a`**=>**`a`**->**`a``square``x`**=**`x``*``x`

- Definitions without arguments and without type signatures are not allowed
to be overloaded. This is called
*the monomorphism restriction*.`answer`**=**6`*`7

- Numeric literals are overloaded, so you would expect
, but one specific type will be chosen depending on how you use
`answer`**::****Num**`a`**=>**`a`.`answer` - If nothing else determines which type
`answer`

should have,*defaulting*rules specific for theclass kick in, and you get**Num**.`answer`**::****Integer** - For code entered directly GHCi, the monomorphism restriction is not used, and there are extended defaulting rules to avoid ambiguities.

- Haskell has a lot in common with preceding functional languages, notably Miranda, Standard ML and Lazy ML.
**Type classes**was the main novel feature in Haskell.- Type classes were primarily intended as an improvement over how Standard ML handled equality and numeric operators.
- Then type classes got extended (with constructor classes, multi-parameter classes, functional depdendencies, …) and are now used for a lot more things than anyone anticipated.
- But David Turner (creator of Miranda) thinks type classes were a mistake :-)

- Standard ML has one built-in type class for equality
(

`==`)**::**''a -> ''a -> Bool

- Predefined numeric operators are overloaded,
(

`*`)**::****Int****->****Int****->****Int**(`*`)**::****Double****->****Double****->****Double**

- but user-defined numeric functions have to choose one specific type.

- We talk about classes, instances and methods in Haskell, so at first sight, type classes in Haskell might seem similar to classes in object oriented languages.
- But they serve different purposes.
- Type classes in Haskell are used to introduce overloaded functions.
- Classes in object oriented languages are used to describe objects…