Concepts of Program Design Data Types Gabriele Keller Ron Vanderfeesten
Compound types • What are types? • So far, we only looked at basic types, such as Int, Boolean, as well as function types Int Bool 1 True 2 … False 3 4 Int -> Bool even odd …
Compound types • But what if we want to define our own, new types • How does it work in different programming languages?
Defining our own type ‘from scratch’ • Example: defining a new type to model colours Colour Green Red Blue
Defining our own type ‘from scratch’ • Example: defining a new type to model colours • Enumeration types in C# enum Colour {Red, Green, Blue}; • In C typedef num Colour {Red, Green, Blue} colour_t; • In Haskell data Colour = Red | Green | Blue
Product types • Defining a new type by combining values of existing types: Int Bool 1 True 2 … False 3 4 Int × Bool (1, True) … (2, False)
Tuples example: modelling a point in a 2D space • In C# public struct Point { public static readonly Point Empty = new Point(); private float x; private float y; public Point(float x, float y) { this.x = x; this.y = y; } public float X { get { return x; } set { x = value; } }
Tuples example: modelling a point in a 2D space • In Java class Point { private float x; private float y; public Point (float x, float y) { this.x = x; this.y = y;} public float getX () {return this.x;} public float getY () {return this.y;} public float setX (float x) {this.x=x;} public float setY (float y) {this.y=y;} }; Point middlePoint (Point p1, Point p2) { Point mid ((p1.getX() + p2.getX())/2.0, (p1.getY() + p2.getY())/2.0); return mid; }
Tuples example: modelling a point in a 2D space • In Java - using degenerate classes in Java: class Point { public float x; public float y; }; Point middlePoint (Point p1, Point p2) { Point mid; mid.x = (p1.x + p2.x)/2.0; mid.y = (p1.y + p2.y)/2.0; return mid; }
Tuples example: modelling a point in a 2D space • In C struct point { float x; float y; }; struct point middlePoint ( struct point p1, struct point p2) { struct point mid; mid.x = (p1.x + p2.x)/2.0; mid.y = (p1.y + p2.y)/2.0; return mid; }
Tuples example: modelling a point in a 2D space • In Haskell: - using simple pairs: type Point = (Float, Float) middlePoint:: Point -> Point -> Point middlePoint (x1, y1) (x2, y2) = ((x1+x2)/2, (y1+y2)/2) middlePoint’ p1 p2 = ((fst p1 + fst p2)/2, (snd p1 + snd p2)/2) - using records (data types with names fields): data Point = Point {x:: Float, y:: Float} middlePoint (Point x1 y1) (Point x2 y2) = Point ((x1+x2)/2) ((y1+y2)/2) middlePoint’ p1 p2 = Point { x = (x p1 + x p2)/2 y = (x p2 + y p2)/2}
Compound types • Composite types that offer alternatives Int Bool 1 True 2 … False 3 4 Int ∪ Bool True 2 … 3 False 4
Sum types • Sum types are composite types that offer alternatives Int Bool 1 True 2 … False 3 4 Int ∪ Bool Int Bool True 2 Bool … Int 3 False 4 Int
Sum types • In Haskell data Value = I Integer | B Bool
Sum-types • Alternatives with varying component types in C: union { int i; float f; } unsafe; unsafe.f = 1.23456; printf “(“%d”, unsafe.i);
Sum-types • Alternatives with varying component types in C: typedef enum {I, F} valueTag; typedef struct { value_t tag; union { int intLit; float floatLit; } val; } value_t;
Sum-types • Alternatives with varying component types in object oriented languages: public abstract class Value { private.Value() {} public class I: Value { public int V; public I(int v) {V = v;} } public class B: Value { public bool V; public B(bool v) {V = v;} }
Recursive types • In Haskell data IntList = ICons Int IntList | Nil • C typedef struct list_node { int elem; struct list_node * next; } int_list_t; • C# class ListNode { int data; ListNode next; public ListNode(int d) { data = d; next = null; }}
Extending MinHs with support for compound types • We add algebraic data types to MinHs - product types - sum types • as well as support for recursive data types • no support for letting the user give new names to these types - could be easily added
Products in MinHs • Products aka pairs in MinHs - minimal extension - no type declaration - no named fields - only pairs ( a 1 , a 2 ) and - nullary tuples/unit () • New MinHs types: - Unit : singleton type with element () - τ 1 * τ 2 : binary product type with element type τ 1 and τ 2 • Operations on these types: - fst and snd to extract the first/second component
Products in MinHs: Concrete and Abstract Syntax • Constructors ( e 1 , e 2 ) Pair e 1 e 2 () UnitEl • Destructors fst e Fst e snd e Snd e • Types τ 1 * τ 2 Cross e 1 e 2 Unit Unit we’ll mostly be using concrete syntax for types
Products in MinHs • Example: recfun div :: ((Int, Int) -> Int) args = if (fst args < snd args) then 0 else div (fst args - snd args, snd args)
Products in MinHs: Static Semantics • Typing rules: Γ ⊢ e 1 : τ 1 Γ ⊢ e 2 : τ 2 Γ ⊢ Pair e 1 e 2 : Cross τ 1 τ 2 Γ ⊢ e: Cross τ 1 τ 2 Γ ⊢ e: Cross τ 1 τ 2 Γ ⊢ Fst e : τ 1 Γ ⊢ Snd e : τ 2 Γ ⊢ UnitEl : Unit
Products in MinHs: Dynamic Semantics • Evaluation rules (M-machine) e 1 ↦ M e 1 ’ e 2 ↦ M e 2 ’ v 1 e 2 ↦ M v 1 e 2 ’ e 1 e 2 ↦ M e 1 ’ e 2 P a i r P a i r P a i r P a i r e ↦ M e’ e ↦ M e’ e ↦ M e ’ e ↦ M e ’ F s t F s t S n d S n d v 1 v 2 ↦ M v 1 v 1 v 2 ↦ M v 2 F s t ( P a i r ) S n d ( P a i r )
Sum-types • Sum-types in MinHs - we use binary sums: ‣ τ 1 +τ 2 : either τ 1 or τ 2 (products: both τ 1 and τ 2 ) - n-ary sums can be expressed by nesting - similarities to the Haskell type Either : data Either a b = Left a | Right b
Sum-types • Types τ 1 + τ 2 Sum τ 1 τ 2 • Constructors Inl e Inl τ 1 τ 2 e Inr e Inr τ 1 τ 2 e • Destructors Case τ 1 τ 2 e ( x.e 1 ) ( y.e 2 ) case e of Inl x -> e 1 Inr y -> e 2
Isomorphic Types • Type correspondence: which MinHs type corresponds to the following Haskell type? data Colour = Red | Green | Blue • We cannot define the same type, but we can define an isomorphic type in MinHs - a type τ 1 is isomorphic to a type τ 2 iff there exists a bijection between τ 1 and τ 2 • Colour is isomorphic to - Unit + (Unit + Unit) and also to - (Unit + Unit) + Unit since all three types have exactly three elements
Isomorphic Types • In actual programming languages, we want to have named user defined types which are distinguished by the type checker: data Direction = North | South | East | West data Colour = Red | Black | Blue | Yellow data Vector = Vector Float Float data Point = Point Float Float
Sums in MinHs: Static Semantics • Typing rules: Γ ⊢ e 1 : τ 1 Γ ⊢ Inl τ 1 τ 2 e 1 : Sum τ 1 τ 2 Γ ⊢ e 2 : τ 2 Sum τ 1 τ 2 Γ ⊢ Inr τ 1 τ 2 e 2 : Γ ⊢ e: Sum τ 1 τ 2 Γ ∪ { x : τ 1 } ⊢ e 1 : τ Γ ∪ { y : τ 2 } ⊢ e 2 : τ Γ ⊢ Case τ 1 τ 2 e ( x .e 1 ) ( y .e 2 ): τ
Sums in MinHs: Dynamic Semantics • Evaluation rules (M-machine), omitting the types for brevity e ↦ M e’ e ↦ M e’ e ↦ M e ’ e ↦ M e ’ I n r I n r I n l I n l e ↦ M e’ Case e ( x . e 1 ) ( y . e 2 ) ↦ M Case e’ ( x . e 1 ) ( y . e 2 ) Case(Inl v ) ( x . e 1 )( y . e 2 ) ↦ M e 1 [ x:=v ] Case(Inr v ) ( x . e 1 )( y . e 2 ) ↦ M e 2 [ y:=v ]
Recursive Types • What about the list type? data IntList = Nil | ICons Int IntList • Can’t be expressed in MinHs yet - we need explicit recursive types! Unit + (Int, ) we need a way to recursively refer to a type! Rec t. Unit + (Int, t )
Recursive types • Types Rec t = τ Rec ( t . τ ) • Constructor Roll e Roll e • Destructor Unroll e Unroll e
Examples • List of integer values: - Type Rec List = Unit + (Int * List) - Terms Roll (Inl ()) [] Roll(Inr (1, Roll (Inl ()))) [1] Roll (Inr (1, Roll(Inr (2, Roll (Inl ())()) [1,2]
Recursive Types in MinHs: Static Semantics • Typing rules: Γ ⊢ e : τ [ t := Rec( t . τ ) ] Rec( t . τ ) Γ ⊢ Roll e : Γ ⊢ e : Rec( t . τ ) τ [ t:= Rec( t . τ ) ] Γ ⊢ Unroll e :
Sums in MinHs: Dynamic Semantics • Evaluation rules (M-machine) e ↦ M e’ e ↦ M e’ e ↦ M e ’ e ↦ M e ’ R o l l R o l l U n r o l l U n r o l l Unroll (Roll e ) ↦ M e
Recommend
More recommend