View
217
Download
0
Embed Size (px)
Citation preview
Cse536 Functional Programming
104/18/23
Lecture #11, Nov. 01, 2004•Special Guest lecture by Tom Harke•Today’s Topics
–The Haskell Class system
–Instance declarations
–Inheritance and dependent classes
–Derived instances
–The Show class
–The Fix operator from homework # 5
•Reading Assignment–Chapter 12 - Qualified Types
–Appendix - A Tour of Haskell’s Standard Type Classes
Sections 24.4 & 24.5
The Show and Read Class (pp 334-340)
•Reminder - Mid-Term Exam Wednesday - next class meeting!
– open book exam
Cse536 Functional Programming
204/18/23
The Haskell Class System
• Think of a Qualified type as a type with a Predicate
• Types which meet those predicates have "extra" functionality.
• A class definition defines the type of the "extra" functionality.
• An instance declarations defines the "extra" functionality for a particular type.
Cse536 Functional Programming
304/18/23
Example Class Definition
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x==y)
class (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
Note defaultdefinition of (/=)
Cse536 Functional Programming
404/18/23
Properties of a class definitionclass (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
• Class name is capitalized, think of this as the name of a type predicate that qualifies the type being described.
• Classes can depend on another class or in other words require another classes as a prerequisite
• The methods of a class are functions whose type can depend upon the type being qualified
• There can be more than one method.• The methods can be ordinary (prefix)
functions or infix operators.
Cse536 Functional Programming
504/18/23
First Example• Example:
– The Class Eq
– Concrete Types without arrows (functions -> ) support equality.
– Assume basic equalities: int_eq, string_eq, bool_eq
• Make the following tree like data types that represent arithmetic expressions, instances of class Eq
data Aop = Add | Sub | Mult | Div
data Aexp = Num Int | Exp (Aexp, Aop, Aexp)
Cse536 Functional Programming
604/18/23
First define equality functions
aop_eq Add Add = True
aop_eq Sub Sub = True
aop_eq Mult Mult = True
aop_eq Div Div = True
aop_eq _ _ = False
aexp_eq (Num x) (Num y) = int_eq x y
aexp_eq (Exp(e1,x,e2))(Exp(f1,y,f2))
= (aexp_eq e1 f1) &&
(aop_eq x y) &&
(aexp_eq e2 f2)
aexp_eq _ _ = False
Cse536 Functional Programming
704/18/23
Then make Instance Definitions• To make an instance
instance Eq(Aop) where
x == y = aop_eq x y
x /= y = not(aop_eq x y )
instance Eq(Aexp) where
x == y = aexp_eq x y
x /= y = not(aexp_eq x y )
• Example use
? (Num 3) == (Num 5)
False
? (Num 3) == (Num (5-2))
True
Cse536 Functional Programming
804/18/23
Another Example: Num Complex• Make Complex numbers an instance of class
Num.
data Complex = C Float Float– An instance of Num, must first be an instance of Eq and
Show and provide methods for (+), (-), and (*) (amongst others).
First provide the numeric operators
complex_add (C x y) (C a b) = C (x+a) (y+b)
complex_sub (C x y) (C a b) = C (x-a) (y-b)
complex_mult (C x y) (C a b)
= C (x*a - y*b) (x*b + a*y)
Cse536 Functional Programming
904/18/23
Num InstanceThen make the instance declarations
instance Eq(Complex) where
(C x y) == (C a b) = x==a && y==b
instance Show(Complex) where
showsPrec = error "No show for complex"
showList = error "No show for complex"
instance Num(Complex) where
x + y = complex_add x y
x - y = complex_sub x y
x * y = complex_mult x y
• Note that the Show instance is quite imprecise, but this will cause an error only if it is ever used
Cse536 Functional Programming
1004/18/23
Full Num Class
class (Eq a, Show a) => Num a where
(+), (-), (*) :: a -> a -> a
negate :: a -> a
abs, signum :: a -> a
fromInteger :: Integer -> a
fromInt :: Int -> a
x - y = x + negate y
fromInt = fromIntegral
Cse536 Functional Programming
1104/18/23
Class Ord• The Class Ord is interesting for several
reasons– It’s a dependant Class, so it uses inheritance
Class Eq a => Ord a where ...– It makes extensive use of default method definitions
• Example: Eq Tree => Ord Tree
data Tree a = Leaf a | Branch (Tree a) (Tree a)
– First make Tree an instance of Eq
instance Eq a => Eq (Tree a) where
(Leaf x) == (Leaf y) = x==y
(Branch x y) == (Branch a b) = x==a && y==b
_ == _ = False
Cse536 Functional Programming
1204/18/23
Make Tree an instance of Ord• First define a (<) and (<=) function for Tree Int
instance (Ord a,Eq a) => Ord(Tree a) where
(Leaf _) < (Branch _ _) = True
(Leaf x) < (Leaf y) = x < y
(Branch _ _) < (Leaf _) = False
(Branch l1 r1) < (Branch l2 r2)
= if l1==l2
then r1 < r2
else l1 < l2
t1 <= t2 = t1 < t2 || t1 == t2
is Eq a really necessary as a dependent type?
Cse536 Functional Programming
1304/18/23
Full Definition of Ordclass (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 = x
| otherwise = y
min x y | x <= y = x
| otherwise = y
An instance need only provide enough methods to define the others. Here compare would be enough or just <= plus Eq a
Cse536 Functional Programming
1404/18/23
A closer look. Classes for Type Constructors
• How do classes work for type constructors like Tree and [-]
• Consider:data Mylist a = Nil | Cons a (Mylist a)
int_list_eq(Nil, Nil) = True
int_list_eq(Cons x xs, Cons y ys) =
(int_eq x y) && (int_list_eq(xs,ys))
int_list_eq (_, _) = False
list_eq :: (a -> a -> Bool) -> (Mylist a,Mylist a) -> Bool
list_eq f (Nil, Nil) = True
list_eq f (Cons x xs, Cons y ys) =
(f x y) && (list_eq f (xs, ys))
list_eq f (_, _) = False
Cse536 Functional Programming
1504/18/23
Classes for Type Constructors
• The function list_eq motivates the following Dependent instance.
instance Eq a => Eq(Mylist a) where
Nil == Nil = True
(Cons x xs) == (Cons y ys) = (x == y) && (xs == ys)
_ == _ = False
? Nil == (Cons 2 Nil)
False
? (Cons 2 Nil) == (Cons (3-1) Nil)
True
What type is (==) used at?
What type is (==) used at?
Cse536 Functional Programming
1604/18/23
Think about this!• Consider :
data Bush a = One a
| Two (Bush a) (Bush a)
| Many [Bush a]
instance Eq a => Eq(Bush a) where
(One x) == (One y) = (x == y)
(Two x1 x2) == (Two y1 y2) = (x1 == y1) && (x2 == y2)
(Many xs) == (Many ys) = (xs == ys)
_ == _ = False
? Many [One 2] == Many [One 2, Two (One 3) (One 5)]
False
? Many [One 3] == Many [One 3]
True
Cse536 Functional Programming
1704/18/23
Analyzeinstance
Eq a => Eq(Bush a) where
(One x) == (One y) = (x == y)
(Two x1 x2) == (Two y1 y2)
= (x1 == y1) && (x2 == y2)
(Many xs) == (Many ys) = (xs == ys)
_ == _ = False
• (==) :: a -> a -> Bool• (==) :: Bush a -> Bush a -> Bool• (==) :: Bush a -> Bush a -> Bool• (==) :: [ Bush a ] -> [ Bush a ] -> Bool
• How do we get (==) ?
Cse536 Functional Programming
1804/18/23
The Class Show• Instances of the Class Show are those types that
can be converted to character strings
show :: Show a => a -> String
• Example uses:
show (2+2) ---> “4”
show (not (3=4)) ---> “True”
Using show and concatenation (++)
“My name is” ++ show name ++ “I am” ++
show age ++ “years old”
• (++) is right associative so this runs in linear time
Cse536 Functional Programming
1904/18/23
Show and Trees• If we try and define a show function for
trees we lose this linear time property. Consider a simplification of Class Show (see the appendix for the real definition):
Instance Show a => Show (Tree a) where
show (Leaf x) = “(Leaf ” ++ show x ++ “)”
show (Branch x y) =
“(Branch” ++ show x ++ show y ++ “)”
When we Show the left sub-tree x, and the right sub-tree y, we end re-concatenating the string returned by the “recursive” call.
Cse536 Functional Programming
2004/18/23
Restoring Linearity• Suppose we had a function shows
shows :: Show a => a -> String -> String
• And shows was part of the Show Class as well.
Class Show a where
show :: a -> String
shows :: a -> String -> String– Where shows has an extra String argument
– Think of this argument as an accumulating parameter, that holds all of the string printed so far.
showsTree :: Show a => Tree a -> String -> String
showsTree (Leaf x) s = “(Leaf ” ++ show x ++ “)” ++ s
showsTree (Branch x y) s =
“(Branch” ++ (showsTree x (showsTree y (“)” ++ s)))
Cse536 Functional Programming
2104/18/23
show can be defined in terms of shows
• showTree tree = showsTree tree “”
• Exercise: write the functionshowsList :: Show a => [a] -> String -> String
showsList [] s = ...
showsList (x:xs) s = ...
Cse536 Functional Programming
2204/18/23
Derived Instances• Some Classes are so useful and so simple to
define, that we’d like the compiler to do it for us.
• Example derivable Classes:– Eq
– Ord
– Show
• Example Uses of deriving classes
data Color = Red | Orange | Yellow | Green
| Blue |Indigo | Violet
deriving Show
data Exp = Int Int | Plus Exp Exp | Minus Exp Exp
deriving (Eq,Show)
Cse536 Functional Programming
2304/18/23
Type propagation in the Class System
• Class information propagates from the use of functions with qualified types into the functions they are used to define:
• Example:
member x [] = False
member x (z:zs) =
if x==z then True else member x zs
• Note that the type of (==)
(==) :: Eq a => a -> a -> Bool
has propagated into the type of member
member :: Eq a => a -> [a] -> Bool
Cse536 Functional Programming
2404/18/23
Implicit invariants of Type Classes• When we define a type class (especially those with
multiple methods) we often want some things to be true about the way the methods interact.
• In Haskell we can’t make these invariants explicit
• E.g.class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x==y)
Invariants
a == b => b == a
a === a
a == b && b == c => a == c
Cse536 Functional Programming
2504/18/23
Another Invariant exampleclass (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
• Invariants– Exactly one of the following is true for all x,y::a
1) x < y
2) x == y
3) x > y
• Transitivity
x <= y && y <= z => x <= z
Cse536 Functional Programming
2604/18/23
The fix point operatorfix :: (a -> a) -> a
fix f = f ( fix f )
• By unrolling the definition of fix we see
fix f = f ( f ( fix f ) )
We get repeated application of f. In fact we get infinite repeated application of f
• Instantiate the type of fix at (b -> c) . We get:
fix :: ((b->c) -> (b->c)) -> (b -> c)
Cse536 Functional Programming
2704/18/23
Use the eta rule
fix :: ((b->c) -> (b->c)) -> (b -> c)
fix f :: b -> c -- for appropriate f
We can eta-expand the definition of fix
fix f n = f (fix f) n
Cse536 Functional Programming
2804/18/23
Example usef fact n = if n=0 then 1 else fact(n-1) * n note f is not recursive
factorial n = fix f n
fix f n = f (fix f) n =if n=0 then 1 else (fix f)(n-1) * n =if n=0 then 1 else f (fix f) (n-1) * n =if n=0 then 1 else if (n-1)=0 then 1 else (fix f) (n-2) * n