algebraic types - gitlab · 2020. 3. 19. · dataexpr = lit integer| add exprexpr| sub exprexpr...
TRANSCRIPT
Algebraic TypesChapter 14 of Thompson
Types so far …
Base types Int, Integer, Float, Bool, CharComposite types:
tuples (t1,t2,…,tn)lists [t1]functions (t1 -> t2)
Algebraic types enumerated, product (record), sum (union)Now, we will see more types that are recursive and polymorphic
Recursive types: example
data NTree = NilT |Node Integer NTree NTree
Such types allow us to build data structures of arbitrary size.
12
10 17
14 20• •
• • • •
Polymorphic types: example
data Maybe a = Nothing | Just a
Built into the Haskell prelude and used for modelling program errors.
Reusable in different situations, such as the built in list type.
Review: algebraic data types in general
data Typename= Con1 t11 t12 … t1i |
Con2 t21 t22 … t2j |…Conm tm1 tm2 … tmk
Each Coni is a constructor, followed by n types, where n ≥ 0, allowing us to build values of the type by using the constructor as a function:Coni :: ti1 -> ti2 -> … -> tin -> Typename
Examples
Enumerated types have constructors with no arguments:data Season = Spring | Summer | Autumn | Winter
Product types have a single constructor:data People = Person Name Age
Sum types have a number of constructors taking different arguments:data Shape = Circle Float |
Rectangle Float Float
Examples: pattern matching
To distinguish among alternatives and to extract components:
area :: Shape -> Floatarea (Circle r) = pi*r*rarea (Rectangle h w) = h*w
Recursive algebraic types: example
A recursive type is a type described in terms of itself:data Expr = Lit Integer |
Add Expr Expr |Sub Expr Expr
This describes an integer expression as something that one of:a literal, like 42;the sum of two subexpressions; orthe difference between two subexpressions
expr1 = Lit 2expr2 = Add (Lit 2) (Lit 3)expr3 = Add (Sub (Lit 3) (Lit 1)) (Lit 3)
Expr
Lit 2
Expr
Add
Lit 2 Lit 3
Expr
Add
Sub Lit 3
Lit 3 Lit 1
Primitive recursion over expressions
[Live coding for eval and show over integer expressions]
Recursive algebraic types: trees
A tree is either nil (empty) or the joining of two subtrees into a tree node:data NTree = NilT |
Node Integer NTree NTreeFor example:
treeEx1 = Node 10 NilT NilTtreeEx2 = Node 17 (Node 14 NilT NilT)
(Node 20 NilT NilT)
Similarly, a list is either the empty list []or constructed from a head and a tail using :
list1 = [10, [], []]list2 = [17, [14, [], []], [20, [], []]]
10
• •
17
14 20
• • • •
Primitive recursion over trees
[live coding for sumTree, depth, occurs]
More recursion over expressions
Since addition is associative, it would be nice to present integer expressions including addition in a normalized right-associative form:
(2+3)+4 = 2+(3+4)((2+3)+4)+5 = 2+(3+(4+5))((2-((6+7)+8))+4)+5 = (2-(6+(7+8)))+(4+5)
Aim: spot occurrences ofAdd (Add e1 e2) e3
and transform them toAdd e1 (Add e2 e3)
[live coding for assoc]
Non-primitive recursion over expressions
assoc :: Expr -> Expr
assoc (Add (Add e1 e2) e3)= assoc (Add e1 (Add e2 e3))
assoc (Add e1 e2) = Add (assoc e1) (assoc e2)
assoc (Sub e1 e2) = Sub (assoc e1) (assoc e2)
assoc (Lit n) = Lit n
Termination
assoc (Add (Add e1 e2) e3)= assoc (Add e1 (Add e2 e3))
The RHS makes progress by moving the expression tree from left-associative to right-associative.None of the other equations move a plus in the other direction, so after applying the above equation some finite number of times there will be no more exposed addition symbols at the top level of the LHS.
Syntax: infix constructors
Can also write:data Expr' = Lit' Integer |
Expr' :+: Expr' |Expr' :-: Expr'
The infix operators must start with :
Mutual recursion
data Person = Adult Name Address Bio |Child Name
data Bio = Parent String [Person] |NonParent String
type Name = Stringtype Address = [String]
Mutual recursion
showPerson (Adult nm ad bio) = show nm ++ show ad ++ showBio bio
showPerson (Child nm) = show nm
showBio (Parent st perList)= st ++ concat (map showPerson perList)
showBio (NonParent st)= st
Polymorphic algebraic types
Type variables can be used to make an algebraic type polymorphic.Example:
data Pairs a = Pr a a
pair1 = Pr 2 3 :: Pairs Intpair2 = Pr [] [3] :: Pairs [Int]pair3 = Pr [] [] :: Pairs [a]
equalPair :: Eq a => Pairs a -> BoolequalPair (Pr x y) = (x==y)
Polymorphic algebraic types: lists
infixr 5 ::: -- same fixity and associativity as list cons :data List a = NilL | a ::: (List a)
deriving (Eq,Ord,Show,Read)A user-defined list type:List a instead of builtin [a]NillL instead of builtin []::: instead of builtin :
2+3 ::: 4+5 ::: NilL5 ::: (9 ::: NilL)
Polymorphic algebraic types: trees
data Tree a = Nil | Node a (Tree a) (Tree a)deriving (Eq,Ord,Show,Read)
depthT :: Tree a -> IntegerdepthT Nil = 0depthT (Node n t1 t2) = 1 + max (depthT t1) (depthT t2)
collapse :: Tree a -> [a]collapse Nil = []collapse (Node x t1 t2)
= collapse t1 ++ [x] ++ collapse t2
Polymorphic algebraic types: trees
collapse (Node 12(Node 34 Nil Nil) (Node 3 (Node 17 Nil Nil) Nil))
= [34, 12, 17, 3]
Polymorphic algebraic types: trees
mapTree :: (a -> b) -> Tree a -> Tree bmapTree f Nil = NilmapTree f (Node x t1 t2)
= Node (f x) (mapTree f t1) (mapTree f t2)
Polymorphic algebraic types: sum types
data Either a b = Left a | Right b
deriving (Eq,Ord,Read,Show)
eitherEG1 = Left "Duke of Prunes”
:: Either String Int
eitherEG2 = Right 33312
:: Either String Int
isLeft :: Either a b -> Bool
isLeft (Left _) = TrueisLeft (Right _) = False
Polymorphic algebraic types: sum types
either :: (a -> c) -> (b -> c) -> Either a b -> c
This is a higher-order function: takes functions as arguments.
Functions can also return functions as results!
either f g (Left x) = f xeither f g (Right y) = g y