Joseph Haugh
University of New Mexico
Given the following data type:
data Foo a = Bar Int Double [String] | Baz Int (Int, Int)
What type does Bar have?
Given the following data type:
data Foo a = Bar Int Double [String] | Baz Int (Int, Int)
What type does Bar have?
Int -> Double -> [String] -> Foo a
What type does Baz have?
Given the following data type:
data Foo a = Bar Int Double [String] | Baz Int (Int, Int)
What type does Bar have?
Int -> Double -> [String] -> Foo a
What type does Baz have?
Int -> (Int, Int) -> Foo a
Given the following data type, function, and instantiation:
data Tree a = Leaf | Node (Tree a) a (Tree a)
foo :: Tree a -> [a]
foo Leaf = []
foo (Node lt a rt) = a : a : (foo lt ++ foo rt)
t :: Tree Int
t = Node (Node Leaf 5 (Node Leaf 6 Leaf)) 3 (Node Leaf 4 Leaf)
What is the value of the following expression?
> foo t
Given the following data type, function, and instantiation:
data Tree a = Leaf | Node (Tree a) a (Tree a)
foo :: Tree a -> [a]
foo Leaf = []
foo (Node lt a rt) = a : a : (foo lt ++ foo rt)
t :: Tree Int
t = Node (Node Leaf 5 (Node Leaf 6 Leaf)) 3 (Node Leaf 4 Leaf)
What is the value of the following expression?
> foo t
[3,3,5,5,6,6,4,4]
Given the following data type, function, and instantiation:
data Tree a = Leaf | Node (Tree a) a (Tree a)
baz :: Num a => Tree a -> Tree (a, a)
baz Leaf = Leaf
baz (Node lt a rt) = Node (baz lt) (a + 1, a * 2) (baz rt)
t :: Tree Int
t = Node (Node Leaf 5 (Node Leaf 6 Leaf)) 3 (Node Leaf 4 Leaf)
What is the value of the following expression?
> baz t
Given the following data type, function, and instantiation:
data Tree a = Leaf | Node (Tree a) a (Tree a)
baz :: Num a => Tree a -> Tree (a, a)
baz Leaf = Leaf
baz (Node lt a rt) = Node (baz lt) (a + 1, a * 2) (baz rt)
t :: Tree Int
t = Node (Node Leaf 5 (Node Leaf 6 Leaf)) 3 (Node Leaf 4 Leaf)
What is the value of the following expression?
> baz t
Node (Node Leaf (6, 10) (Node Leaf (7, 12) Leaf)) (4, 6) (Node Leaf (5, 8) Leaf)
Does that actually work thought the way it is shown??
Let’s try it…
We get this error:
:7:1: error:
• No instance for (Show (Tree (Int, Int)))
arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
What does that mean?
It is telling us that Haskell doesn’t know how to print or Show this value.
How do we fix this?
We need to instance Tree into Show.
The Show typeclass asks us to define a single function:
show :: a -> String
Where the a in this case is our Tree a.
instance Show a => Show (Tree a) where
show Leaf = "Leaf"
show (Node lt a rt) =
"Node (" ++ show lt ++ ") " ++
show a ++
" (" ++ show rt ++ ")"
or
instance Show a => Show (Tree a) where
show Leaf = "Leaf"
show (Node lt a rt) = concat [
"Node (", show lt, ") ",
show a,
" (", show rt, ")"]
Let’s now take a step back and look at the Eq typeclass.
This typeclass defines what it means for a datatype to define equality.
Its declaration looks like this:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x /= y = not (x == y)
This means that both (==) and (/=) take 2 as and return a Bool and that (/=) can be derived from (==).
What is a here?
It is whatever type you are instancing into Eq.
For example if we were to instance Bool into Eq it might look like this:
instance Eq Bool where
-- (==) Bool -> Bool -> Bool
False == False = True
True == True = True
_ == _ = False
Here a is equal to Bool.
Notice we do not have to define (/=) since it can be derived from (==).
Recall that :i will tell us all this information within ghci.
> :i Eq
...
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
{-# MINIMAL (==) | (/=) #-}
...
MINIMAL is the least amount of functions we need to define in order to be a member of the class. In this case we can define (==) or (/=).
Given the following datatype:
data Direction = North | East | South | West
Give a minimal instance for Direction into Eq
instance Eq Direction where
North == North = True
East == East = True
South == South = True
West == West = True
_ == _ = False
Recall the definition of the Ord typeclass:
class Eq a => Ord a where
(<), (<=), (>), (>=) :: a -> a -> Bool
max, min :: a -> a -> a
min x y | x <= y = x
| otherwise = y
max x y | x <= y = y
| otherwise = x
MINIMAL compare | (<=)
Here the typeclass has an Eq constrain on a.
This means that a type must already be a member of Eq in order to be a member of Ord.
Instance Direction into Ord where North < East < South < West
data Direction = North | East | South | West
class Eq a => Ord a where
(<), (<=), (>), (>=) :: a -> a -> Bool
max, min :: a -> a -> a
min x y | x <= y = x
| otherwise = y
max x y | x <= y = y
| otherwise = x
-- {MINIMAL compare | (<=)}
Instance Direction into Ord where North < East < South < West
data Direction = North | East | South | West
instance Ord Direction where
North <= _ = True
_ <= West = True
East <= South = True
d1 <= d2
| d1 == d2 = True
| otherwise = False
Boring right?
When something is boring try to automate it!
Haskell already does automate simple instances like this!
We could have just done this:
data Direction = North | East | South | West
deriving (Eq, Ord)
Done!
There are times where you will want to create your own custom instance.
For example what if we had this data type:
data ListInt = Empty | ConsLI Int ListInt
and we wanted to instance it into Eq and Ord but for the Ord instance we will say that a list is greater than another list if its sum is greater.
data ListInt = Empty | ConsLI Int ListInt
deriving (Eq)
sumLI :: ListInt -> Int
sumLI Empty = 0
sumLI (ConsLI x xs) = x + sumLI xs
instance Ord ListInt where
Empty <= _ = True
li1@(ConsLI x xs) <= li2@(ConsLI y ys) =
sumLI li1 <= sumLI li2
_ <= _ = False
> (ConsLI 1 (ConsLI 2 (ConsLI 3 Empty))) <= (ConsLI 7 Empty)
True
> (ConsLI 1 (ConsLI 2 (ConsLI 3 Empty))) <= (ConsLI 6 Empty)
True
> (ConsLI 1 (ConsLI 2 (ConsLI 3 Empty))) <= (ConsLI 5 Empty)
False
Could we do this for our more general List data type?
data List a = Nil | Cons a (List a)
Let’s try:
data List a = Nil | Cons a (List a)
deriving (Eq)
sumL :: Num a => List a -> a
sumL Nil = 0
sumL (Cons x xs) = x + sumL xs
instance (Num a, Eq a, Ord a) => Ord (List a) where
Nil <= _ = True
l1@(Cons x xs) <= l2@(Cons y ys) =
sumL l1 <= sumL l2
_ <= _ = False
> (Cons 1 (Cons 2 (Cons 3 Nil))) <= (Cons 7 Nil)
True
> (Cons 1 (Cons 2 (Cons 3 Nil))) <= (Cons 5 Nil)
False
> (Cons 'a' Nil) <= (Cons 'b' Nil)
• No instance for (Num Char) arising from a use of ‘<=’
• In the expression: (Cons 'a' Nil) <= (Cons 'b' Nil)
In an equation for ‘it’: it = (Cons 'a' Nil) <= (Cons 'b' Nil)