Record Systems Dylan Just YOW LambdaJam 2015 Haskell Elm - - PowerPoint PPT Presentation

record systems
SMART_READER_LITE
LIVE PREVIEW

Record Systems Dylan Just YOW LambdaJam 2015 Haskell Elm - - PowerPoint PPT Presentation

Record Systems Dylan Just YOW LambdaJam 2015 Haskell Elm PureScript OCaml Idris Pascal Haskell Java classes Elm Scala classes PureScript C structs OCaml Database tables Idris Pascal Haskell Elm PureScript Haskell Elm


slide-1
SLIDE 1

Record Systems

Dylan Just YOW LambdaJam 2015

slide-2
SLIDE 2

Haskell Elm PureScript OCaml Idris Pascal

slide-3
SLIDE 3

Haskell Elm PureScript OCaml Idris Pascal Java classes Scala classes C structs Database tables

slide-4
SLIDE 4

Haskell Elm PureScript

slide-5
SLIDE 5

Haskell Elm PureScript Vinyl

slide-6
SLIDE 6

Haskell Elm PureScript Vinyl

slide-7
SLIDE 7

What are records? What can they do?

slide-8
SLIDE 8

Structural typing Row polymorphism

slide-9
SLIDE 9

What is a record?

slide-10
SLIDE 10

Set of fields with

  • name
  • type
  • value

Record =

slide-11
SLIDE 11

Set of fields with

  • name
  • type
  • value

Record =

type-level information value-level information

slide-12
SLIDE 12

Set of fields with

  • name
  • type
  • value

Record =

slide-13
SLIDE 13

Basic Operations

slide-14
SLIDE 14

Declare Type

data Person = Person {name::String, age::Int}

haskell

slide-15
SLIDE 15

Instantiate

data Person = Person {name::String, age::Int} bob = Person {name="Bob", age=30}

haskell

slide-16
SLIDE 16

Get

data Person = Person {name::String, age::Int} bob = Person {name="Bob", age=30} bobName = name bob

haskell

slide-17
SLIDE 17

Set

data Person = Person {name::String, age::Int} bob = Person {name="Bob", age=30} bobName = name bob

  • lderBob = bob {age=31}

haskell

slide-18
SLIDE 18

Haskell Problems

slide-19
SLIDE 19

Namespacing

slide-20
SLIDE 20

data Pos2D = Pos2D {x::Int, y::Int} data Pos3D = Pos3D {x::Int, y::Int, z::Int}

haskell

slide-21
SLIDE 21

data Pos2D = Pos2D {x::Int, y::Int} data Pos3D = Pos3D {x::Int, y::Int, z::Int}

haskell

slide-22
SLIDE 22

data Pos2D = Pos2D {x::Int, y::Int} data Pos3D = Pos3D {x::Int, y::Int, z::Int}

Compile error

haskell

slide-23
SLIDE 23

Namespacing.hs:2:22: Multiple declarations of ‘x’ Declared at: Namespacing.hs:1:22 Namespacing.hs:2:22 Namespacing.hs:2:32: Multiple declarations of ‘y’ Declared at: Namespacing.hs:1:32 Namespacing.hs:2:32

haskell

slide-24
SLIDE 24

Overlapping Record Names

slide-25
SLIDE 25

data Key = StringKey { key :: String } | NumericKey { key :: Int }

haskell

slide-26
SLIDE 26

data Key = StringKey { key :: String } | NumericKey { key :: Int }

Compile error

haskell

slide-27
SLIDE 27

Constructors StringKey and NumericKey give different types for field ‘key’ In the data declaration for ‘Key’

haskell

slide-28
SLIDE 28

Partial Accessors

slide-29
SLIDE 29

data Shape = Circle {radius::Int} | Rectangle {width::Int, height::Int}

haskell

slide-30
SLIDE 30

data Shape = Circle {radius::Int} | Rectangle {width::Int, height::Int} r = Rectangle {width=3, height=4}

haskell

slide-31
SLIDE 31

data Shape = Circle {radius::Int} | Rectangle {width::Int, height::Int} r = Rectangle {width=3, height=4} r_radius = case r of (Circle {radius=r}) -> r (Rectangle {}) -> -1 > r_radius

  • 1

haskell

slide-32
SLIDE 32

data Shape = Circle {radius::Int} | Rectangle {width::Int, height::Int} r = Rectangle {width=3, height=4} r_radius = radius r > r_radius' *** Exception: No match in record selector radius

Run-time error

haskell

slide-33
SLIDE 33
slide-34
SLIDE 34

Haskell vs PureScript

slide-35
SLIDE 35

Namespacing

slide-36
SLIDE 36

data Pos2D = Pos2D {x::Int, y::Int} data Pos3D = Pos3D {x::Int, y::Int, z::Int}

Compile error

haskell

slide-37
SLIDE 37

data Pos2D = Pos2D {x::Number,y::Number} data Pos3D = Pos3D {x::Number,y::Number,z::Number}

purescript

slide-38
SLIDE 38

Overlapping Record Names

slide-39
SLIDE 39

data Key = StringKey { key :: String } | NumericKey { key :: Int }

Compile error

haskell

slide-40
SLIDE 40

data Key = StringKey { key :: String } | NumericKey { key :: Number }

purescript

slide-41
SLIDE 41

Partial Accessors

slide-42
SLIDE 42

data Shape = Circle {radius::Int} | Rectangle {width::Int, height::Int} r = Rectangle {width=3, height=4} r_radius = radius r > r_radius' *** Exception: No match in record selector radius

Run-time error

haskell

slide-43
SLIDE 43

data Shape = Circle {radius::Int} | Rectangle {width::Int, height::Int} r = Rectangle {width=3, height=4} r_radius = case r of (Circle {radius=rad}) -> rad (Rectangle {}) -> -1 > r_radius

  • 1

haskell

slide-44
SLIDE 44

data Shape = Circle {radius::Number} | Rectangle {width::Number, height::Number} r = Rectangle {width:3, height:4} r_radius = case r of (Circle {radius=rad}) -> rad (Rectangle {}) -> -1 > r_radius

  • 1

purescript

slide-45
SLIDE 45

data Shape = Circle {radius::Int} | Rectangle {width::Int, height::Int} r = Rectangle {width=3, height=4} r_radius = case r of (Circle r') -> r' (Rectangle w' h') -> -1 > r_radius

  • 1

haskell

slide-46
SLIDE 46

data Shape = Circle {radius::Number} | Rectangle {width::Number, height::Number} r = Rectangle {width:3, height:4} r_radius = case r of (Circle c') -> c'.radius (Rectangle r') -> -1 > r_radius

  • 1

purescript

slide-47
SLIDE 47

r_radius = case r of (Circle r') -> r' (Rectangle w' h') -> -1 r_radius = case r of (Circle c') -> c'.radius (Rectangle r') -> -1

purescript haskell

slide-48
SLIDE 48

data Shape = Circle {radius::Int} | Rectangle {width::Int, height::Int} c = Circle {radius=3} c' = Circle 3

haskell

slide-49
SLIDE 49

data Shape = Circle { radius::Int } | Rectangle { width::Int, height::Int }

Fields are constructor parameters

haskell

slide-50
SLIDE 50

data Shape = Circle { radius::Number } | Rectangle { width::Number, height::Number }

Records are constructor parameters

purescript

slide-51
SLIDE 51

data X = X { a :: String }

purescript

slide-52
SLIDE 52

data X = X { a :: String } data Y = Y String {a :: String}

purescript

slide-53
SLIDE 53

data X = X { a :: String } data Y = Y String {a :: String} data Z = Z {a::String,b::Number} Number {c::String}

purescript

slide-54
SLIDE 54

data X = X { a :: String } data Y = Y String {a :: String} data Z = Z {a::String,b::Number} Number {c::String} type Q = {a::String, b::Int}

purescript

slide-55
SLIDE 55

data X = X { a :: String } data Y = Y String {a :: String} data Z = Z {a::String,b::Number} Number {c::String} type Q = {a::String, b::Int} Tagged Untagged

purescript

slide-56
SLIDE 56

Tagged vs Untagged

slide-57
SLIDE 57

Tagged data Pos2D = Pos2D {x::Number,y::Number} p = Pos2D {x:3,y:4} Untagged type Pos2D = {x::Number,y::Number} p = {x:3,y:4}

purescript

slide-58
SLIDE 58

Nominal Type data Pos2D = Pos2D {x::Number,y::Number} p = Pos2D {x:3,y:4} Structural Type type Pos2D = {x::Number,y::Number} p = {x:3,y:4}

purescript

slide-59
SLIDE 59

Nominal Typing Two values are type-compatible iff their declarations name the same type.

slide-60
SLIDE 60

Structural Typing Two values are type-compatible iff they exhibit the same structure.

slide-61
SLIDE 61

Structural Typing

slide-62
SLIDE 62

Extensible Records Row Polymorphism Record Subtyping

slide-63
SLIDE 63

Extensible Records Row Polymorphism Record Subtyping

slide-64
SLIDE 64

Extensible Records

  • add fields
  • remove fields
slide-65
SLIDE 65

PureScript Elm

slide-66
SLIDE 66

Create > bob = {name="bob"} {name="bob"} : {name:String}

elm

slide-67
SLIDE 67

Add Field > bob = {name="bob"} {name="bob"} : {name:String} > bob' = {bob | age=33} {name="bob",age=33} : {name:String,age:number}

elm

slide-68
SLIDE 68

Remove Field > bob = {name="bob"} {name="bob"} : {name:String} > bob' = {bob | age=33} {name="bob",age=33} : {name:String,age:number} > bob'' = {bob' - age} {name="bob"} : {name:String}

elm

slide-69
SLIDE 69

Row Polymorphism

slide-70
SLIDE 70

Back to PureScript...

slide-71
SLIDE 71

type House = {color::String,rooms::Number} type Car = {color::String,model::String}

purescript

slide-72
SLIDE 72

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse :: House myhouse = {color:"pink",rooms:3} mycar :: Car mycar = {color:"red",model:"Corolla"}

purescript

slide-73
SLIDE 73

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"}

purescript

slide-74
SLIDE 74

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"} getColor :: House -> String getColor x = x.color getColor' :: Car -> String getColor' x = x.color

purescript

slide-75
SLIDE 75

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"} getColor :: forall r. {color::String | r} -> String getColor x = x.color

purescript

slide-76
SLIDE 76

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"} getColor :: forall r. {color::String | r} -> String getColor x = x.color > getColor myhouse "pink"

purescript

slide-77
SLIDE 77

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"} getColor :: forall r. {color::String | r} -> String getColor x = x.color > getColor mycar "red"

purescript

slide-78
SLIDE 78

getColor :: forall r. {color::String | r} -> String

Any other fields Required fields

purescript

slide-79
SLIDE 79

getColor :: forall r. {color::String | r} -> String

Polymorphic Row Variable Required fields

purescript

slide-80
SLIDE 80

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"} getColor :: forall r. {color::String | r} -> String getColor x = x.color

purescript

slide-81
SLIDE 81

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"} lighten::forall r.{color::String|r} -> {color::String|r} lighten x = x { color = "light " ++ x.color }

purescript

slide-82
SLIDE 82

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"} lighten::forall r.{color::String|r} -> {color::String|r} lighten x = x { color = "light " ++ x.color } > getColor (lighten myhouse) "light pink"

purescript

slide-83
SLIDE 83

type House = {color::String,rooms::Number} type Car = {color::String,model::String} myhouse = {color:"pink",rooms:3} mycar = {color:"red",model:"Corolla"} lighten::forall r.{color::String|r} -> {color::String|r} lighten x = x { color = "light " ++ x.color } > getColor (lighten mycar) "light red"

purescript

slide-84
SLIDE 84

Haskell strikes back!

slide-85
SLIDE 85

Type-level Strings

slide-86
SLIDE 86

data Person = Person {firstName::String, lastName::String} bob :: Person bob = Person {firstName="bob", lastName="cuttey"} bobFirstName = firstName bob bobLastName = lastName bob

haskell

slide-87
SLIDE 87

type Person = Map String String bob' :: Person bob' = fromList [("firstName", "bob"), ("lastName", "cuttey")] bobFirstName' = bob' ! "firstName" bobLastName' = bob' ! "lastName"

haskell

slide-88
SLIDE 88

bob = Person {firstName="bob", lastName="cuttey"} bob' = fromList [("firstName", "bob"), ("lastName", "cuttey")]

haskell

slide-89
SLIDE 89

bob = Person {firstName="bob", lastName="cuttey"} bob' = fromList [("firstName", "bob"), ("lastName", "cuttey")]

String Field name

haskell

slide-90
SLIDE 90

bob = Person {firstName="bob", lastName="cuttey"} bob' = fromList [("firstName", "bob"), ("lastName", "cuttey")]

Value-level information Type-level information

haskell

slide-91
SLIDE 91

Kind Type Value

type of type of haskell

slide-92
SLIDE 92

Kind * Type String Value "hello"

haskell

slide-93
SLIDE 93

Kind * Symbol Type String "firstName" Value "hello"

  • haskell
slide-94
SLIDE 94

Kind * Symbol Type String "firstName" Value "hello"

  • Value-level String

Type-level String

haskell

slide-95
SLIDE 95

data Field (fieldName::Symbol) a = Field a bob :: Field "firstName" String bob = Field "bob"

haskell

slide-96
SLIDE 96

data Field (fieldName::Symbol) a = Field a bob :: Field "firstName" String bob = Field "bob" name type value

haskell

slide-97
SLIDE 97

Vinyl

slide-98
SLIDE 98

{-# LANGUAGE DataKinds, KindSignatures TypeOperators, GADTs, MultiParamTypeClasses #-} import Data.Vinyl get key rec = getField (rget key rec)

haskell

slide-99
SLIDE 99

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String)

SField Constructor SField Type Constructor

haskell

slide-100
SLIDE 100

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String)

Field Name Field Type

haskell

slide-101
SLIDE 101

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String)

Pair type

haskell

slide-102
SLIDE 102

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String)

Type-level String Type Pair type

haskell

slide-103
SLIDE 103

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String) bob = firstName =: "bob" <+> lastName =: "cuttey"

haskell

slide-104
SLIDE 104

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String) bob = firstName =: "bob" <+> lastName =: "cuttey"

Create record with 1 field

haskell

slide-105
SLIDE 105

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String) bob = firstName =: "bob" <+> lastName =: "cuttey"

Append records

haskell

slide-106
SLIDE 106

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String) bob = firstName =: "bob" <+> lastName =: "cuttey" bobFirstName = get firstName bob bobLastName = get lastName bob

haskell

slide-107
SLIDE 107

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String) bob = firstName =: "bob" <+> lastName =: "cuttey" bobFirstName = get firstName bob bobLastName = get lastName bob dog = firstName =: "doggie" dogFirstName = get firstName dog

haskell

slide-108
SLIDE 108

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String) bob = firstName =: "bob" <+> lastName =: "cuttey" bobFirstName = get firstName bob bobLastName = get lastName bob dog = firstName =: "doggie" dogFirstName = get firstName dog

haskell

slide-109
SLIDE 109

firstName = SField :: SField '("firstName", String) lastName = SField :: SField '("lastName", String) bob = firstName =: "bob" <+> lastName =: "cuttey" bobFirstName = get firstName bob bobLastName = get lastName bob dog = firstName =: "doggie" dogFirstName = get firstName dog

Row polymorphism!

haskell

slide-110
SLIDE 110

In conclusion...

slide-111
SLIDE 111

Record = {(Name, Type, Value)}

slide-112
SLIDE 112

Define record type Instantiate type Get field Set field Add field Remove field

slide-113
SLIDE 113

Structural typing

  • Extensible records
  • Row Polymorphism
slide-114
SLIDE 114

Built-in record systems: Elm > PureScript > Haskell

slide-115
SLIDE 115

Vinyl library

slide-116
SLIDE 116

Cheers!

Slides and code at https://github.com/techtangents/recordsystemstalk