...
 
Commits (10)
Copyright Author name here (c) 2019
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Author name here nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
import Distribution.Simple
main = defaultMain
---------------------------------------------
-- 1. Eq: defines equality and inequality. --
---------------------------------------------
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
-- Minimum complete definition: (==) OR (/=)
-- GHCI examples:
-- :t (==)
-- :t (/=)
-- 2 == 3
-- 3 == 3
-- Example instance...
data Color = Red | Green | Blue
instance Eq Color where
(==) Red Red = True
(==) Green Green = True
(==) Blue Blue = True
(==) _ _ = False
-- Alternatively, use automatic derivation!
-- Say: how haskell derives the equality operator
-- Todo: look through ordering derivation
data Color2 = Red2 | Green2 | Blue2
deriving (Eq)
------------------------------------------------
-- 2. Ord: defines functions that compare values.
------------------------------------------------
-- Built in ordering type:
data Ordering = LT | EQ | GT
-- Typeclass definition.
class (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
compare x y | x == y = EQ -- a must have implemented ==
| x <= y = LT
| otherwise = GT
x <= y = compare x y /= GT
x < y = compare x y == LT
x >= y = compare x y /= LT
x > y = compare x y == GT
max x y | x <= y = y
| otherwise = x
min x y | x <= y = x
| otherwise = y
-- Minimum complete definition:
-- compare OR <=
-- GHCI examples
-- :t compare
-- :t (<=)
-- compare 2.0 2.1
-- compare 'a' 'b'
-- 2.0 <= 2.1
-- Hoogle Ord
-- Look at laws of ORD.
-- Hoogle: Ord a => [a] -> [a]
-- Example instance
--
-- By hand: write instnaces for Eq / Ord / Show
instance Ord Color where
compare Red Red = EQ
compare Green Green = EQ
compare Blue Blue = EQ
compare Red Green = LT
compare Red Blue = LT
compare Green Blue = LT
compare _ _ = GT
-- ...
-- Deriving Ord works here.
-------------------------------------
-- 3. Num: the basic numeric typeclass
-------------------------------------
class Num a where
(+), (-), (*) :: a -> a -> a
-- | Unary negation.
negate :: a -> a
-- | Absolute value.
abs :: a -> a
-- | Sign of a number.
signum :: a -> a
-- | Conversion from an 'Integer'.
fromInteger :: Integer -> a
x - y = x + negate y
negate x = 0 - x
-- Minimal complete definition: (+), (*), abs, signum, fromInteger, and negate (or (-)).
-----------------------------------------------------
-- 4. Enum: operations on sequentially ordered types.
-----------------------------------------------------
class Enum a where
succ, pred :: a -> a -- Successor / predecessor of a value
toEnum :: Int -> a -- Convert from an Int
fromEnum :: a -> Int -- Convert to an Int
enumFrom :: a -> [a] -- [n..]
enumFromThen :: a -> a -> [a] -- [n,n'..]
enumFromTo :: a -> a -> [a] -- [n..m]
enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
succ = toEnum . (+ 1) . fromEnum
pred = toEnum . (subtract 1) . fromEnum
enumFrom x = map toEnum [fromEnum x ..]
enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
-- Minimum complete definition:
-- toEnum and fromEnum
-- Example instance:
data Color = Red | Green | Blue
deriving (Read, Show, Eq, Ord, Enum)
-- TODO: add example Red .. Blue
-- GHCI examples
-- :t toEnum
-- :t fromEnum
-- take 10 $ enumFromThen 2 4
-- take 10 $ enumFromTo 1 100
----------------------------------------------------------------
-- 5. Read and Show: converting strings to values and vice versa
----------------------------------------------------------------
-- This is the machinery we invoke when we type
-- "deriving Show" after declaring a custom type.
-- A little complicated, and the details don't matter too much.
-- TODO: add examples on read and show when they're introduced.
-- omit read from here; but talk about show.
type ShowS = String -> String
class Show a where
showsPrec :: Int -> a -> ShowS
show :: a -> String
showList :: [a] -> ShowS
showsPrec _ x s = show x ++ s
show x = showsPrec 0 x ""
-- ... default decl for showList given in Prelude
-- Minimal complete definition: showsPrec or show
-- Other important typeclasses
-- Integral (Int, Integer)
-- Fractional (Double)
-- Floating (Double)
-- RealFrac (round, truncate)
module Main where
main :: IO ()
main = do
putStrLn "hello world"
-- Suppose we define a new type, Color.
data Color = Red | Green | Blue
-- (==)
-- We might want to define an equality check for it.
colorEq :: Color -> Color -> Bool
colorEq Red Red = True
colorEq Green Green = True
colorEq Blue Blue = True
colorEq _ _ = False
-- Suppose that (==) didn't exist.
-- We might implement a function, stringEq as follows.
stringEq :: [Char] -> [Char] -> Bool
stringEq [] [] = True
stringEq (x:xs) (y:ys) = (x == y) && stringEq xs ys
stringEq _ _ = False
-- But this is super inefficient - we have to write separate functions
-- for each notion of "equality" that we want to encode.
-- Introducing typeclasses:
-- This allows us to give different definitions of a function
-- for different types.
-- These are not classes, similar to the notion of _interfaces_ in Java.
-- Example typeclass: BasicEq
class BasicEq a where
isEqual :: a -> a -> Bool
-- Example _instance_ of the BasicEq typeclass on booleans.
instance BasicEq Bool where
isEqual True True = True
isEqual False False = True
isEqual _ _ = False
-- isEqual True True now works
-- isEqual "Hi" "Hi2" will not
-- Expanding on this: we can define a more sophisticated typeclass
-- with multiple functions. For a type to be in the "BasicEq2" type class,
-- it must implement _one of_ "isEqual2" and "isNotEqual2".
-- Need to put types for all functions
-- But the implementations are optional
class BasicEq2 a where
isEqual2 :: a -> a -> Bool
isEqual2 x y = not (isNotEqual2 x y)
isNotEqual2 :: a -> a -> Bool
isNotEqual2 x y = not (isEqual2 x y)
-- We can make `Color` an instance of
-- `BasicEq2` by implementing `isEqual2`.
-- Compiler is really smart, it will figure out the other.
-- everything to left of => is a type constraint
instance BasicEq2 Color where
isEqual2 Red Red = True
isEqual2 Green Green = True
isEqual2 Blue Blue = True
isEqual2 _ _ = False
-- Want to spend time
-- Look at source of Eq
-- :info
-- Look at docs
-- Look at Show
-- :t show
instance Show Color where
show Red = "Red"
show Green = "Green"
show Blue = "Blue"
-- Automatic typeclass derivation!
-- Ord: typeclass for ordering
-- Read: "inverse" of Show
data Color2 = Red2 | Green2 | Blue2
deriving (Read, Show, Eq, Ord)
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-3.5
# resolver: nightly-2015-09-21
# resolver: ghc-7.10.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2018-01-01.yaml
resolver: lts-13.3
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# - location:
# git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver
# using the same syntax as the packages field.
# (e.g., acme-missiles-0.3)
# extra-deps: []
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=1.9"
#
# Override the architecture used by stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor
name: week3
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/githubuser/week3#readme
license: BSD3
license-file: LICENSE
author: Author name here
maintainer: example@example.com
copyright: 2019 Author name here
category: Web
build-type: Simple
cabal-version: >=1.10
extra-source-files: README.md
executable week3
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5
......@@ -34,8 +34,9 @@ this page will be updated throughout the course with new material.
1. [Algebraic Datatypes](notes/Algebraic_Datatypes.html): Defining and using types in Haskell, and the basics of type algebra.
1. Typeclasses<!--[Typeclasses](notes/Typeclasses.html)-->: Using, writing, and
deriving typeclasses, and the power of polymorphism.
1. [Typeclasses](notes/Typeclasses.html): Introducing typeclasses and polymorphism.
1. [Typeclasses II, Batteries Included](notes/TypeclassesII.html): More on the built-in typeclasses in Haskell.
## Algebraic Abstractions
......
......@@ -2,28 +2,38 @@
title: Typeclasses
---
## Motivation
## Motivation: Equality testing with `(==)`
We have seen that every Haskell function has a type signature that specifies
the types of its arguments. These types can be completely specific, as in
Suppose we define the following `Color` type, and want to implement an equality test for it.
```haskell
doubleInt :: Int -> Int
doubleInt x = 2 * x
data Color = Red | Green | Blue
```
or can contain type variables, as in
A naive strategy would be to do the following:
```haskell
fst :: (a,b) -> a
fst (x,_) = x
-- Source: RWH, Ch. 6
colorEq :: Color -> Color -> Bool
colorEq Red Red = True
colorEq Green Green = True
colorEq Blue Blue = True
colorEq _ _ = False
```
where `a` and `b` can be any type. While polymorphic functions like `fst` give
us some flexibility in what types a function can accept, there are cases where
we might want the same function to work on different types in a manner that
cannot be captured in a single polymorphic implementation. For example, we might
want a function
Now, suppose we want to create an equality test for strings. We might define a function like this:
```haskell
-- Source: RWH, Ch. 6
stringEq :: [Char] -> [Char] -> Bool
stringEq [] [] = True
stringEq (x:xs) (y:ys) = x == y && stringEq xs ys
stringEq _ _ = False
```
As you might've noticed, writing a separate function for every equality test is not great.
We really want a function
```haskell
(==) :: a -> a -> Bool
......@@ -38,7 +48,12 @@ some types (such as functions) might not have a reasonable implementation of
## A Typeclass to the Rescue
A typeclass allows us to give different definitions of a function for different
types. It can be seen as an extensible interface to some set of functions, and solves
types<label for="java-interfaces"
class="margin-toggle sidenote-number"></label>.
<span class="sidenote">
This is similar to the notion of <a href="http://tutorials.jenkov.com/java/interfaces.html">interfaces in Java</a>.
</span>
It can be seen as an extensible interface to some set of functions, and solves
exactly the problem presented above. Consider the real type signature of `(==)`,
```haskell
......@@ -58,7 +73,7 @@ class Eq a where
```
This tells us that for a type `a` to be an instance of `Eq`, we must define a
function with type `a -> a -> Bool`. Many primitive Haskell types are already
function `(==)` with type `a -> a -> Bool`. Many primitive Haskell types are already
instances of `Eq`, for example
```haskell
......@@ -68,98 +83,52 @@ Prelude> True == False
False
```
However, assume we wanted to implement `(==)` for the type
```haskell
data Maybe a = Just a | Nothing
```
To do so, we need to make `Maybe a` an instance of the `Eq` typeclass.
```haskell
instance Eq a => Eq (Maybe a) where
(==) (Just x) (Just y) = x == y
(==) Nothing Nothing = True
(==) _ _ = False
```
All we are doing here is defining `(==)` for the type `Maybe a`. Note that we have a
typeclass constraint on `a` being in `Eq`, since otherwise we could not have `x
== y` in the second line.
## Some Common Typeclasses<label for="haskell-2010"
class="margin-toggle sidenote-number">
</label>
<input type="checkbox"
id="haskell-2010"
class="margin-toggle"/>
<span class="sidenote">
These typeclasses are all part of the [Haskell 2010](https://www.haskell.org/onlinereport/haskell2010/haskellch6.html)
standard. Note that the type hierarchy given there no longer exactly that in the GHC Prelude.
</span>
### Eq
## Built-in Eq typeclass
Equality.
Indeed, here is the definition of the built-in `Eq` typeclass:
```haskell
class Eq a where
(==), (/=) :: a -> a -> Bool
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
x /= y = not (x == y)
x == y = not (x /= y)
```
Note minimial complete definition.
Importantly, we only need to implement _one of_ `==` or `/=`, since the compiler can figure out the other function by applying `not`.
### Ord
Ordering can be represented in Haskell using the built-in type
Now, suppose we wanted to implement `(==)` for the `Color` type defined above. We just need to make `Color` an instance of the `Eq` typeclass. Indeed, we can write
```haskell
data Ordering = LT | EQ | GT
instance Eq Color where
(==) Red Red = True
(==) Green Green = True
(==) Blue Blue = True
(==) _ _ = False
```
The typeclass `Ord` defined functions that compare values.
Similarly, if we wanted to make `Maybe a` an instance of `Eq`, we could write:
```haskell
class (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
compare x y | x == y = EQ
| x <= y = LT
| otherwise = GT
x <= y = compare x y /= GT
x < y = compare x y == LT
x >= y = compare x y /= LT
x > y = compare x y == GT
max x y | x <= y = y
| otherwise = x
min x y | x <= y = x
| otherwise = y
instance Eq a => Eq (Maybe a) where
(==) (Just x) (Just y) = x == y
(==) Nothing Nothing = True
(==) _ _ = False
```
Note that we have a typeclass constraint on `a` being in `Eq`, since otherwise we could not have `x == y` in the second line.
Defining either `compare` or `==` and `<=` for a type gives a minimal complete
definition.
## Automatic derivation
Note the class constraint
### Enum
It turns out that GHC can automatically derive instances for certain typeclasses. Instead of manually writing `instance Eq Color` above, we can just write
```haskell
data Color = Red | Green | Blue
deriving (Read, Show, Eq, Ord)
```
### Num
```haskell
```
On the type `Color`, this will automatically implement functions for string parsing (`Read`), string printing (`Show`), equality testing (`Eq`), and ordering (`Ord`).
### Show
### References
### Read
[_Real World Haskell_, Chapter 6](http://book.realworldhaskell.org/read/using-typeclasses.html).
---
title: Typeclasses II, Batteries Included
---
## Introduction
This page aims to highlight some of main typeclasses available in `Prelude`. The diagram below, from the [2010 Haskell report](https://www.haskell.org/definition/haskell2010.pdf) is a useful summary. Arrows from `A` to `B` indicate that `B` has a typeclass constraint of `A`.
<img width="500px" src="/images/typeclasses.png"></img>
## Batteries included: Some common typeclasses<label for="haskell-2010"
class="margin-toggle sidenote-number">
</label>
<input type="checkbox"
id="haskell-2010"
class="margin-toggle"/>
<span class="sidenote">
These typeclasses are all part of the [Haskell 2010](https://www.haskell.org/onlinereport/haskell2010/haskellch6.html)
standard. Note that the type hierarchy given there no longer exactly that in the GHC Prelude.
</span>
### Eq
The `Eq` class defines equality (`==`) and inequality (`/=`). All basic datatypes in Prelude are instances of `Eq`.
```haskell
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
```
Note that it suffices to define either (==) or (/=), but not both. The compiler can use the presence of one to compute the value of the other. For more on the properties of `Eq`, see [here](http://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#t:Eq).
### Ord
The `Ord` typeclass defines functions that compare values. Ordering can be represented in Haskell using the built-in type
```haskell
data Ordering = LT | EQ | GT
```
The typeclass definition is below. Note the constraint `Eq a` - this allows us to use equality testing in the definition below.
```haskell
class (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
compare x y | x == y = EQ
| x <= y = LT
| otherwise = GT
x <= y = compare x y /= GT
x < y = compare x y == LT
x >= y = compare x y /= LT
x > y = compare x y == GT
max x y | x <= y = y
| otherwise = x
min x y | x <= y = x
| otherwise = y
```
Defining either `compare` or `<=` is sufficient for a minimal complete definition. See [here](http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Ord.html#t:Ord) for more properties.
### Show
The typeclass `Show` handles conversion of values to readable `String`s. This is the machinery used whenever we write `deriving (Show)` for custom types.
```haskell
class Show a where
showsPrec :: Int -> a -> ShowS
show :: a -> String
showList :: [a] -> ShowS
showsPrec _ x s = show x ++ s
show x = showsPrec 0 x ""
-- ... default decl for showList given in Prelude
```
Defining either `showsPrec` or `show` is sufficient for a minimal completion definition. See [here](http://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#t:Show) for more properties.
### Enum
The typeclass `Enum` defines operations on sequentially ordered types. This is the typeclass used in Haskell's translation of values like `[n..m]`.
The default Prelude declaration is below.
```haskell
class Enum a where
succ, pred :: a -> a -- Successor / predecessor of a value
toEnum :: Int -> a -- Convert from an Int
fromEnum :: a -> Int -- Convert to an Int
enumFrom :: a -> [a] -- [n..]
enumFromThen :: a -> a -> [a] -- [n,n'..]
enumFromTo :: a -> a -> [a] -- [n..m]
enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
succ = toEnum . (+ 1) . fromEnum
pred = toEnum . (subtract 1) . fromEnum
enumFrom x = map toEnum [fromEnum x ..]
enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
```
It suffices to define `toEnum` and `fromEnum` for a complete definition. See [here](http://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#t:Enum) for more properties and documentation.
### Num
The typeclass `Num` defines the basic numeric class. The default Prelude declaration is below.
```haskell
class Num a where
(+), (-), (*) :: a -> a -> a
-- | Unary negation.
negate :: a -> a
-- | Absolute value.
abs :: a -> a
-- | Sign of a number.
signum :: a -> a
-- | Conversion from an 'Integer'.
fromInteger :: Integer -> a
x - y = x + negate y
negate x = 0 - x
```
For a minimal complete definition, we must define `(+)`, `(*)`, `abs`, `signum`, `fromInteger`, and `negate` (or `(-)`).
## References
- https://www.haskell.org/onlinereport/haskell2010/haskellch6.html
- http://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#t:Read