Composite Data Types as Algebra, Logic Recursive Types Algebraic Data Types Christine Rizkallah CSE, UNSW (and data61) Term 3 2019 1
Composite Data Types as Algebra, Logic Recursive Types Composite Data Types Most of the types we have seen so far are basic types, in the sense that they represent built-in machine data representations. Real programming languages feature ways to compose types together to produce new types, such as: 2
Composite Data Types as Algebra, Logic Recursive Types Composite Data Types Most of the types we have seen so far are basic types, in the sense that they represent built-in machine data representations. Real programming languages feature ways to compose types together to produce new types, such as: Tuples Structs Records
Composite Data Types as Algebra, Logic Recursive Types Composite Data Types Most of the types we have seen so far are basic types, in the sense that they represent built-in machine data representations. Real programming languages feature ways to compose types together to produce new types, such as: Classes Tuples Structs Records
Composite Data Types as Algebra, Logic Recursive Types Composite Data Types Most of the types we have seen so far are basic types, in the sense that they represent built-in machine data representations. Real programming languages feature ways to compose types together to produce new types, such as: Classes Tuples Structs Unions Records 5
Composite Data Types as Algebra, Logic Recursive Types Combining values conjunctively We want to store two things in one value. (might want to use non-compact slides for this one) Haskell Tuples type Point = (Float, Float) midpoint (x1,y1) (x2,y2) = ((x1+x2)/2, (y1+y2)/2) 6
Composite Data Types as Algebra, Logic Recursive Types Combining values conjunctively We want to store two things in one value. (might want to use non-compact slides for this one) Haskell Datatypes data Point = Pnt { x :: Float Haskell Tuples , y :: Float } type Point = (Float, Float) midpoint (Pnt x1 y1) (Pnt x2 y2) midpoint (x1,y1) (x2,y2) = ((x1+x2)/2, (y1+y2)/2) = ((x1+x2)/2, (y1+y2)/2) midpoint' p1 p2 = = ((x p1 + x p2) / 2, (y p1 + y p2) / 2) 7
Composite Data Types as Algebra, Logic Recursive Types Combining values conjunctively We want to store two things in one value. (might want to use non-compact slides for this one) Haskell Datatypes C Structs data Point = typedef struct point { Pnt { x :: Float float x; Haskell Tuples , y :: Float float y; } type Point = (Float, Float) } point; point midPoint (point p1, point p2) { midpoint (Pnt x1 y1) (Pnt x2 y2) midpoint (x1,y1) (x2,y2) point mid; = ((x1+x2)/2, (y1+y2)/2) = ((x1+x2)/2, (y1+y2)/2) mid.x = (p1.x + p2.x) / 2.0; mid.y = (p2.y + p2.y) / 2.0; midpoint' p1 p2 = return mid; = ((x p1 + x p2) / 2, } (y p1 + y p2) / 2) 8
Composite Data Types as Algebra, Logic Recursive Types Combining values conjunctively We want to store two things in one value. (might want to use non-compact slides for this one) Haskell Datatypes C Structs data Point = Java typedef struct point { Pnt { x :: Float float x; class Point { Haskell Tuples , y :: Float float y; public float x; } type Point = (Float, Float) } point; public float y; point midPoint (point p1, point p2) { } midpoint (Pnt x1 y1) (Pnt x2 y2) midpoint (x1,y1) (x2,y2) point mid; Point midPoint (Point p1, Point p2) { = ((x1+x2)/2, (y1+y2)/2) = ((x1+x2)/2, (y1+y2)/2) mid.x = (p1.x + p2.x) / 2.0; Point mid = new Point(); mid.y = (p2.y + p2.y) / 2.0; mid.x = (p1.x + p2.x) / 2.0; midpoint' p1 p2 = return mid; mid.y = (p2.y + p2.y) / 2.0; = ((x p1 + x p2) / 2, } return mid; (y p1 + y p2) / 2) } 9
Composite Data Types as Algebra, Logic Recursive Types Combining values conjunctively We want to store two things in one value. (might want to use non-compact slides for this one) Haskell Datatypes C Structs data Point = Java typedef struct point { “Better” Java Pnt { x :: Float float x; class Point { Haskell Tuples , y :: Float class Point { float y; public float x; private float x; } type Point = (Float, Float) } point; private float y; public float y; public Point (float x, float y) { point midPoint (point p1, point p2) { } this.x = x; this.y = y; midpoint (Pnt x1 y1) (Pnt x2 y2) midpoint (x1,y1) (x2,y2) point mid; Point midPoint (Point p1, Point p2) { } = ((x1+x2)/2, (y1+y2)/2) public float getX() {return this.x;} = ((x1+x2)/2, (y1+y2)/2) mid.x = (p1.x + p2.x) / 2.0; Point mid = new Point(); public float getY() {return this.y;} mid.y = (p2.y + p2.y) / 2.0; mid.x = (p1.x + p2.x) / 2.0; public float setX(float x) {this.x=x;} midpoint' p1 p2 = public float setY(float y) {this.y=y;} return mid; mid.y = (p2.y + p2.y) / 2.0; = ((x p1 + x p2) / 2, } } return mid; Point midPoint (Point p1, Point p2) { (y p1 + y p2) / 2) return new Point((p1.getX() + p2.getX()) / 2.0, } (p2.getY() + p2.getY()) / 2.0); } 10
Composite Data Types as Algebra, Logic Recursive Types Product Types In MinHS, we will have a very minimal way to accomplish this, called a product type : τ 1 × τ 2 We won’t have type declarations, named fields or anything like that. More than two values can be combined by nesting products, for example a three dimensional vector: Int × ( Int × Int ) 11
Composite Data Types as Algebra, Logic Recursive Types Constructors and Eliminators We can construct a product type similar to Haskell tuples: Γ ⊢ e 1 : τ 1 Γ ⊢ e 2 : τ 2 Γ ⊢ ( e 1 , e 2 ) : τ 1 × τ 2 The only way to extract each component of the product is to use the fst and snd eliminators: Γ ⊢ e : τ 1 × τ 2 Γ ⊢ e : τ 1 × τ 2 Γ ⊢ fst e : τ 1 Γ ⊢ snd e : τ 2 12
Composite Data Types as Algebra, Logic Recursive Types Examples Example (Midpoint) recfun midpoint :: (( Int × Int ) → ( Int × Int ) → ( Int × Int )) p 1 = recfun midpoint ′ :: (( Int × Int ) → ( Int × Int )) p 2 = ((fst p 1 + fst p 2 ) ÷ 2 , (snd p 1 + snd p 2 ) ÷ 2) Example (Uncurried Division) recfun div :: (( Int × Int ) → Int ) args = if (fst args < snd args ) then 0 else div (fst args − snd args , snd args ) 13
Composite Data Types as Algebra, Logic Recursive Types Dynamic Semantics e 1 �→ M e ′ e 2 �→ M e ′ 1 2 ( e 1 , e 2 ) �→ M ( e ′ ( v 1 , e 2 ) �→ M ( v 1 , e ′ 1 , e 2 ) 2 ) e �→ e ′ e �→ e ′ fst e �→ M fst e ′ snd e �→ M snd e ′ fst ( v 1 , v 2 ) �→ M v 1 snd ( v 1 , v 2 ) �→ M v 2 14
Composite Data Types as Algebra, Logic Recursive Types Unit Types Currently, we have no way to express a type with just one value. This may seem useless at first, but it becomes useful in combination with other types. We’ll introduce a type, 1 , pronounced unit , that has exactly one inhabitant, written () : Γ ⊢ () : 1 15
Composite Data Types as Algebra, Logic Recursive Types Disjunctive Composition We can’t, with the types we have, express a type with exactly three values. Example (Trivalued type) data TrafficLight = Red | Amber | Green 16
Composite Data Types as Algebra, Logic Recursive Types Disjunctive Composition We can’t, with the types we have, express a type with exactly three values. Example (Trivalued type) data TrafficLight = Red | Amber | Green In general we want to express data that can be one of multiple alternatives, that contain different bits of data. Example (More elaborate alternatives) type Length = Int type Angle = Int data Shape = Rect Length Length | Circle Length | Point | Triangle Angle Length Length This is awkward in many languages. In Java we’d have to use inheritance. In C we’d have to use unions. 17
Composite Data Types as Algebra, Logic Recursive Types Sum Types We will use sum types to express the possibility that data may be one of two forms. τ 1 + τ 2 This is similar to the Haskell Either type. Our TrafficLight type can be expressed (grotesquely) as a sum of units: TrafficLight ≃ 1 + ( 1 + 1 ) 18
Composite Data Types as Algebra, Logic Recursive Types Constructors and Eliminators for Sums To make a value of type τ 1 + τ 2 , we invoke one of two constructors: Γ ⊢ e : τ 1 Γ ⊢ e : τ 2 Γ ⊢ InL e : τ 1 + τ 2 Γ ⊢ InR e : τ 1 + τ 2 We can branch based on which alternative is used using pattern matching: Γ ⊢ e : τ 1 + τ 2 x : τ 1 , Γ ⊢ e 1 : τ y : τ 2 , Γ ⊢ e 2 : τ Γ ⊢ ( case e of InL x → e 1 ; InR y → e 2 ) : τ (Using concrete syntax here, for readability.) (Feel free to replace it with abstract syntax of your choosing.) 19
Composite Data Types as Algebra, Logic Recursive Types Examples Example (Traffic Lights) Our traffic light type has three values as required: TrafficLight ≃ 1 + ( 1 + 1 ) ≃ InL () Red Amber ≃ InR (InL () ) ≃ InR (InR () ) Green 20
Composite Data Types as Algebra, Logic Recursive Types Examples We can convert most (non-recursive) Haskell types to equivalent MinHs types now. Replace all constructors with 1 1 Add a × between all constructor arguments. 2 Change the | character that separates constructors to a +. 3 Example data Shape = Rect Length Length | Circle Length | Point | Triangle Angle Length Length ≃ 1 × ( Int × Int ) + 1 × Int + 1 + 1 × ( Int × ( Int × Int )) 21
Recommend
More recommend