galois tech talk / vinyl: records in haskell and type theory
DESCRIPTION
Records in Haskell are notoriously difficult to compose; many solutions have been proposed. Vinyl lies in the space of library-level approaches, and addresses polymorphism, extensibility, effects and strictness. I describe how Vinyl approaches record families over arbitrary key spaces using a Tarski universe construction, as well as a method for immersing each field of a record in a chosen effect modality. Also discussed are presheaves, sheaves and containers.TRANSCRIPT
Vinyl: Records in Haskelland Type Theory
Jon Sterlingjonmsterling.com
August 12, 2014
Records in GHC 7.8
I Haskell records are nominally typedI They may not share field names
data R = R { x :: X }data R’ = R’ { x :: X } −− ˆ Error
Records in GHC 7.8
I Haskell records are nominally typed
I They may not share field names
data R = R { x :: X }data R’ = R’ { x :: X } −− ˆ Error
Records in GHC 7.8
I Haskell records are nominally typedI They may not share field names
data R = R { x :: X }data R’ = R’ { x :: X } −− ˆ Error
Records in GHC 7.8
I Haskell records are nominally typedI They may not share field names
data R = R { x :: X }
data R’ = R’ { x :: X } −− ˆ Error
Records in GHC 7.8
I Haskell records are nominally typedI They may not share field names
data R = R { x :: X }data R’ = R’ { x :: X } −− ˆ Error
Structural typing
I Sharing field names and accessorsI Record types may be characterized structurally
Structural typing
I Sharing field names and accessors
I Record types may be characterized structurally
Structural typing
I Sharing field names and accessorsI Record types may be characterized structurally
Row polymorphism
How do we express the type of a function which adds afield to a record?
Row polymorphism
How do we express the type of a function which adds afield to a record?
Row polymorphism
How do we express the type of a function which adds afield to a record?
x : {foo : A}f(x) : {foo : A, bar : B}
Row polymorphism
How do we express the type of a function which adds afield to a record?
x : {foo : A; ~rs}f(x) : {foo : A, bar : B; ~rs}
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ where
RNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[]
(:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])
class ss ⊆ (rs :: [∗]) wherecast :: Rec rs→ Rec ss
(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss
(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss(=:) : s ::: t→ t→ Rec ’[s ::: t]
(⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)
lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
data (s :: Symbol) ::: (t :: ∗) = Field
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
class s ∈ (rs :: [∗])class ss ⊆ (rs :: [∗]) where
cast :: Rec rs→ Rec ss(=:) : s ::: t→ t→ Rec ’[s ::: t](⊕) : Rec ss→ Rec ts→ Rec (ss ++ ts)lens : s ::: t ∈ rs⇒ s ::: t→ Lens’ (Rec rs) t
Roll your own in Haskell
f :: Rec (”foo” ::: A ’: rs)→ Rec (”bar” ::: B ’: ”foo” ::: A ’: rs)
Roll your own in Haskell
f :: Rec (”foo” ::: A ’: rs)→ Rec (”bar” ::: B ’: ”foo” ::: A ’: rs)
Why be stringly typed?
I Let’s generalize our key space
Why be stringly typed?
I Let’s generalize our key space
Old
We relied on a single representation for keys as pairs ofstrings and types.
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
Proposed
We put the keys in an arbitrary type (kind) and describetheir semantics with a function el (for elements).
data Rec :: [∗]→ ∗ whereRNil :: Rec ’[](:&) :: !t→ !(Rec rs)→ Rec ((s ::: t) ’: rs)
Proposed
We put the keys in an arbitrary type (kind) and describetheir semantics with a function el (for elements).
data Rec :: (el :: k→ ∗)→ (rs :: [k])→ ∗ whereRNil :: Rec el ’[](:&) :: ∀(r :: k) (rs’:: [k]). !(el r)→ !(Rec el rs)→ Rec (r ’: rs’)
Proposed
We put the keys in an arbitrary type (kind) and describetheir semantics with a function el (for elements).
data Rec :: (k→ ∗)→ [k]→ ∗ whereRNil :: Rec el ’[](:&) :: !(el r)→ !(Rec el rs)→ Rec (r ’: rs)
Actual
Type families are not functions, but in many cases cansimulate them using Richard Eisenberg’s techniqueoutlined in Defunctionalization for the win.
data TyFun :: ∗ → ∗ → ∗
type family (f :: TyFun k l→ ∗) $ (x :: k) :: l
data Rec :: (TyFun k ∗ → ∗)→ [k]→ ∗ whereRNil :: Rec el ’[](:&) :: !(el $ r)→ !(Rec el rs)→ Rec el (r ’: rs)
Actual
Type families are not functions, but in many cases cansimulate them using Richard Eisenberg’s techniqueoutlined in Defunctionalization for the win.
data TyFun :: ∗ → ∗ → ∗type family (f :: TyFun k l→ ∗) $ (x :: k) :: l
data Rec :: (TyFun k ∗ → ∗)→ [k]→ ∗ whereRNil :: Rec el ’[](:&) :: !(el $ r)→ !(Rec el rs)→ Rec el (r ’: rs)
Actual
Type families are not functions, but in many cases cansimulate them using Richard Eisenberg’s techniqueoutlined in Defunctionalization for the win.
data TyFun :: ∗ → ∗ → ∗type family (f :: TyFun k l→ ∗) $ (x :: k) :: l
data Rec :: (TyFun k ∗ → ∗)→ [k]→ ∗ whereRNil :: Rec el ’[](:&) :: !(el $ r)→ !(Rec el rs)→ Rec el (r ’: rs)
Example
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email Label
data SLabel :: Label→ ∗ whereSHome :: SLabel HomeSWork :: SLabel Work
Example
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email Label
data SLabel :: Label→ ∗ whereSHome :: SLabel HomeSWork :: SLabel Work
Example
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email Label
data SLabel :: Label→ ∗
data SAddrKeys :: AddrKeys→ ∗ whereSName :: SAddrKeys NameSPhone :: SLabel l→ SAddrKeys (Phone l)SEmail :: SLabel l→ SAddrKeys (Email l)
Example
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email Label
data SLabel :: Label→ ∗data SAddrKeys :: AddrKeys→ ∗ where
SName :: SAddrKeys NameSPhone :: SLabel l→ SAddrKeys (Phone l)SEmail :: SLabel l→ SAddrKeys (Email l)
Example
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email Label
data SLabel :: Label→ ∗data SAddrKeys :: AddrKeys→ ∗
data ElAddr :: (TyFun AddrKeys ∗)→ ∗ whereElAddr :: ElAddr el
type instance ElAddr $ Name = Stringtype instance ElAddr $ (Phone l) = [N]type instance ElAddr $ (Email l) = String
type AddrRec rs = Rec ElAddr rs
Example
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email Label
data SLabel :: Label→ ∗data SAddrKeys :: AddrKeys→ ∗
data ElAddr :: (TyFun AddrKeys ∗)→ ∗ whereElAddr :: ElAddr el
type instance ElAddr $ Name = Stringtype instance ElAddr $ (Phone l) = [N]type instance ElAddr $ (Email l) = String
type AddrRec rs = Rec ElAddr rs
Example
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email Label
data SLabel :: Label→ ∗data SAddrKeys :: AddrKeys→ ∗
data ElAddr :: (TyFun AddrKeys ∗)→ ∗ whereElAddr :: ElAddr el
type instance ElAddr $ Name = Stringtype instance ElAddr $ (Phone l) = [N]type instance ElAddr $ (Email l) = String
type AddrRec rs = Rec ElAddr rs
Sugared example
import Data.Singletons as S
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email LabelS.genSingletons [ ’’Label, ’’AddrKeys ]
makeUniverse ’’AddrKeys ”ElAddr”
type instance ElAddr $ Name = Stringtype instance ElAddr $ (Phone l) = [N]type instance ElAddr $ (Email l) = String
type AddrRec rs = Rec ElAddr rs
Sugared example
import Data.Singletons as S
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email LabelS.genSingletons [ ’’Label, ’’AddrKeys ]
makeUniverse ’’AddrKeys ”ElAddr”
type instance ElAddr $ Name = Stringtype instance ElAddr $ (Phone l) = [N]type instance ElAddr $ (Email l) = String
type AddrRec rs = Rec ElAddr rs
Sugared example
import Data.Singletons as S
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email LabelS.genSingletons [ ’’Label, ’’AddrKeys ]
makeUniverse ’’AddrKeys ”ElAddr”
type instance ElAddr $ Name = Stringtype instance ElAddr $ (Phone l) = [N]type instance ElAddr $ (Email l) = String
type AddrRec rs = Rec ElAddr rs
Sugared example
import Data.Singletons as S
data Label = Home |Workdata AddrKeys = Name | Phone Label | Email LabelS.genSingletons [ ’’Label, ’’AddrKeys ]
makeUniverse ’’AddrKeys ”ElAddr”
type instance ElAddr $ Name = Stringtype instance ElAddr $ (Phone l) = [N]type instance ElAddr $ (Email l) = String
type AddrRec rs = Rec ElAddr rs
Example records
bob :: AddrRec [Name, Email Work]bob = SName =: ”Robert W. Harper”⊕ SEmail SWork =: ”[email protected]”
jon :: AddrRec [Name, Email Work, Email Home]jon = SName =: ”Jon M. Sterling”⊕ SEmail SWork =: ”[email protected]”⊕ SEmail SHome =: ”[email protected]”
Example records
bob :: AddrRec [Name, Email Work]bob = SName =: ”Robert W. Harper”⊕ SEmail SWork =: ”[email protected]”
jon :: AddrRec [Name, Email Work, Email Home]jon = SName =: ”Jon M. Sterling”⊕ SEmail SWork =: ”[email protected]”⊕ SEmail SHome =: ”[email protected]”
Recovering HList
data Id :: (TyFun k k)→ ∗ wheretype instance Id $ x = x
type HList rs = Rec Id rs
ex :: HList [Z, Bool, String]ex = 34 :& True :& ”vinyl” :& RNil
Recovering HList
data Id :: (TyFun k k)→ ∗ wheretype instance Id $ x = x
type HList rs = Rec Id rs
ex :: HList [Z, Bool, String]ex = 34 :& True :& ”vinyl” :& RNil
Recovering HList
data Id :: (TyFun k k)→ ∗ wheretype instance Id $ x = x
type HList rs = Rec Id rs
ex :: HList [Z, Bool, String]ex = 34 :& True :& ”vinyl” :& RNil
Recovering HList
data Id :: (TyFun k k)→ ∗ wheretype instance Id $ x = x
type HList rs = Rec Id rs
ex :: HList [Z, Bool, String]ex = 34 :& True :& ”vinyl” :& RNil
Validating records
validateName :: String→ Either Error StringvalidateEmail :: String→ Either Error StringvalidatePhone :: [N]→ Either Error [N]
*unnnnnhhh...*
validateContact:: AddrRec [Name, Email Work]→ Either Error (AddrRec [Name, Email Work])
Validating records
validateName :: String→ Either Error StringvalidateEmail :: String→ Either Error StringvalidatePhone :: [N]→ Either Error [N]
*unnnnnhhh...*
validateContact:: AddrRec [Name, Email Work]→ Either Error (AddrRec [Name, Email Work])
Validating records
validateName :: String→ Either Error StringvalidateEmail :: String→ Either Error StringvalidatePhone :: [N]→ Either Error [N]
*unnnnnhhh...*
validateContact:: AddrRec [Name, Email Work]→ Either Error (AddrRec [Name, Email Work])
Welp.
Effects inside records
data Rec :: (TyFun k ∗ → ∗)→ [k]→ ∗ whereRNil :: Rec el ’[](:&) :: !(el $ r)→ !(Rec el rs)→ Rec el (r ’: rs)
Effects inside records
data Rec :: (TyFun k ∗ → ∗)→ (∗ → ∗)→ [k]→ ∗ whereRNil :: Rec el f ’[](:&) :: !(f (el $ r))→ !(Rec el f rs)→ Rec el f (r ’: rs)
Effects inside records
data Rec :: (TyFun k ∗ → ∗)→ (∗ → ∗)→ [k]→ ∗ whereRNil :: Rec el f ’[](:&) :: !(f (el $ r))→ !(Rec el f rs)→ Rec el f (r ’: rs)
(=:) : Applicative f⇒ sing r→ el $ r→ Rec el f ’[r]k =: x = pure x :& RNil
(⇐ \): sing r→ f (el $ r)→ Rec el f ’[r]k⇐ \ x = x :& RNil
Effects inside records
data Rec :: (TyFun k ∗ → ∗)→ (∗ → ∗)→ [k]→ ∗ whereRNil :: Rec el f ’[](:&) :: !(f (el $ r))→ !(Rec el f rs)→ Rec el f (r ’: rs)
(=:) : Applicative f⇒ sing r→ el $ r→ Rec el f ’[r]k =: x = pure x :& RNil
(⇐ \): sing r→ f (el $ r)→ Rec el f ’[r]k⇐ \ x = x :& RNil
Effects inside records
data Rec :: (TyFun k ∗ → ∗)→ (∗ → ∗)→ [k]→ ∗ whereRNil :: Rec el f ’[](:&) :: !(f (el $ r))→ !(Rec el f rs)→ Rec el f (r ’: rs)
(=:) : Applicative f⇒ sing r→ el $ r→ Rec el f ’[r]k =: x = pure x :& RNil
(⇐ \): sing r→ f (el $ r)→ Rec el f ’[r]k⇐ \ x = x :& RNil
Compositional validation
type Validator a = a→ Either Error a
Compositional validation
newtype Lift o f g x = Lift { runLift :: f x ‘o‘ g x }type Validator = Lift (→) Identity (Either Error)
Compositional validation
newtype Lift o f g x = Lift { runLift :: f x ‘o‘ g x }type Validator = Lift (→) Identity (Either Error)
validateName :: AddrRec Validator ’[Name]validatePhone :: ∀l. AddrRec Validator ’[Phone l]validateEmail :: ∀l. AddrRec Validator ’[Email l]
type TotalContact =[ Name, Email Home, Email Work, Phone Home, Phone Work ]
validateContact :: AddrRec Validator TotalContactvalidateContact = validateName
⊕ validateEmail ⊕ validateEmail⊕ validatePhone ⊕ validatePhone
Compositional validation
newtype Lift o f g x = Lift { runLift :: f x ‘o‘ g x }type Validator = Lift (→) Identity (Either Error)
validateName :: AddrRec Validator ’[Name]validatePhone :: ∀l. AddrRec Validator ’[Phone l]validateEmail :: ∀l. AddrRec Validator ’[Email l]
type TotalContact =[ Name, Email Home, Email Work, Phone Home, Phone Work ]
validateContact :: AddrRec Validator TotalContactvalidateContact = validateName
⊕ validateEmail ⊕ validateEmail⊕ validatePhone ⊕ validatePhone
Compositional validation
newtype Lift o f g x = Lift { runLift :: f x ‘o‘ g x }type Validator = Lift (→) Identity (Either Error)
validateName :: AddrRec Validator ’[Name]validatePhone :: ∀l. AddrRec Validator ’[Phone l]validateEmail :: ∀l. AddrRec Validator ’[Email l]
type TotalContact =[ Name, Email Home, Email Work, Phone Home, Phone Work ]
validateContact :: AddrRec Validator TotalContactvalidateContact = validateName
⊕ validateEmail ⊕ validateEmail⊕ validatePhone ⊕ validatePhone
Compositional validation
newtype Lift o f g x = Lift { runLift :: f x ‘o‘ g x }type Validator = Lift (→) Identity (Either Error)
validateName :: AddrRec Validator ’[Name]validatePhone :: ∀l. AddrRec Validator ’[Phone l]validateEmail :: ∀l. AddrRec Validator ’[Email l]
type TotalContact =[ Name, Email Home, Email Work, Phone Home, Phone Work ]
validateContact :: AddrRec Validator TotalContactvalidateContact = validateName
⊕ validateEmail ⊕ validateEmail⊕ validatePhone ⊕ validatePhone
Record effect operators
( ? ) :: Rec el (Lift (→) f g) rs→ Rec el f rs→ Rec el g rs
rtraverse :: Applicative h⇒(∀ x. f x→ h (g x))→Rec el f rs→ h (Rec el g rs)
rdist :: Applicative f⇒ Rec el f rs→ f (Rec el Identity rs)rdist = rtraverse (fmap Identity)
Record effect operators
( ? ) :: Rec el (Lift (→) f g) rs→ Rec el f rs→ Rec el g rs
rtraverse :: Applicative h⇒(∀ x. f x→ h (g x))→Rec el f rs→ h (Rec el g rs)
rdist :: Applicative f⇒ Rec el f rs→ f (Rec el Identity rs)rdist = rtraverse (fmap Identity)
Record effect operators
( ? ) :: Rec el (Lift (→) f g) rs→ Rec el f rs→ Rec el g rs
rtraverse :: Applicative h⇒(∀ x. f x→ h (g x))→Rec el f rs→ h (Rec el g rs)
rdist :: Applicative f⇒ Rec el f rs→ f (Rec el Identity rs)rdist = rtraverse (fmap Identity)
Record effect operators
( ? ) :: Rec el (Lift (→) f g) rs→ Rec el f rs→ Rec el g rs
rtraverse :: Applicative h⇒(∀ x. f x→ h (g x))→Rec el f rs→ h (Rec el g rs)
rdist :: Applicative f⇒ Rec el f rs→ f (Rec el Identity rs)rdist = rtraverse (fmap Identity)
Compositional validation
bob :: AddrRec [Name, Email Work]validateContact :: AddrRec Validator TotalContact
bobValid :: AddrRec (Either Error) [Name, Email Work]bobValid = cast validateContact ? bob
validBob :: Either Error (AddrRec Identity [Name, Email Work])validBob = rdist bobValid
Compositional validation
bob :: AddrRec [Name, Email Work]validateContact :: AddrRec Validator TotalContact
bobValid :: AddrRec (Either Error) [Name, Email Work]bobValid = cast validateContact ? bob
validBob :: Either Error (AddrRec Identity [Name, Email Work])validBob = rdist bobValid
Compositional validation
bob :: AddrRec [Name, Email Work]validateContact :: AddrRec Validator TotalContact
bobValid :: AddrRec (Either Error) [Name, Email Work]bobValid = cast validateContact ? bob
validBob :: Either Error (AddrRec Identity [Name, Email Work])validBob = rdist bobValid
Laziness as an effect
newtype Identity a = Identity { runIdentity :: a }data Thunk a = Thunk { unThunk :: a }
type PlainRec el rs = Rec el Identity rstype LazyRec el rs = Rec el Thunk rs
Laziness as an effect
newtype Identity a = Identity { runIdentity :: a }data Thunk a = Thunk { unThunk :: a }
type PlainRec el rs = Rec el Identity rstype LazyRec el rs = Rec el Thunk rs
Laziness as an effect
newtype Identity a = Identity { runIdentity :: a }data Thunk a = Thunk { unThunk :: a }
type PlainRec el rs = Rec el Identity rs
type LazyRec el rs = Rec el Thunk rs
Laziness as an effect
newtype Identity a = Identity { runIdentity :: a }data Thunk a = Thunk { unThunk :: a }
type PlainRec el rs = Rec el Identity rstype LazyRec el rs = Rec el Thunk rs
Concurrent records with Async
fetchName :: AddrRec IO ’[Name]fetchName = SName⇐\ runDB nameQuery
fetchWorkEmail :: AddrRec IO ’[Email Work]fetchWorkEmail = SEmail SWork⇐\ runDB emailQuery
fetchBob :: AddrRec IO [Name, Email Work]fetchBob = fetchName ⊕ fetchWorkEmail
Concurrent records with Async
fetchName :: AddrRec IO ’[Name]fetchName = SName⇐\ runDB nameQuery
fetchWorkEmail :: AddrRec IO ’[Email Work]fetchWorkEmail = SEmail SWork⇐\ runDB emailQuery
fetchBob :: AddrRec IO [Name, Email Work]fetchBob = fetchName ⊕ fetchWorkEmail
Concurrent records with Async
fetchName :: AddrRec IO ’[Name]fetchName = SName⇐\ runDB nameQuery
fetchWorkEmail :: AddrRec IO ’[Email Work]fetchWorkEmail = SEmail SWork⇐\ runDB emailQuery
fetchBob :: AddrRec IO [Name, Email Work]fetchBob = fetchName ⊕ fetchWorkEmail
Concurrent records with Async
fetchName :: AddrRec IO ’[Name]fetchName = SName⇐\ runDB nameQuery
fetchWorkEmail :: AddrRec IO ’[Email Work]fetchWorkEmail = SEmail SWork⇐\ runDB emailQuery
fetchBob :: AddrRec IO [Name, Email Work]fetchBob = fetchName ⊕ fetchWorkEmail
Concurrent records with Async
newtype Concurrently a= Concurrently { runConcurrently :: IO a }
( $ ) :: (∀ a. f a→ g a)→ Rec el f rs→ Rec el g rs
bobConcurrently :: Rec el Concurrently [Name, Email Work]bobConcurrently = Concurrently $ fetchBob
concurrentBob :: IO (PlainRec el [Name, Email Work])concurrentBob = runConcurrently (rdist bobConcurrently)
Concurrent records with Async
newtype Concurrently a= Concurrently { runConcurrently :: IO a }
( $ ) :: (∀ a. f a→ g a)→ Rec el f rs→ Rec el g rs
bobConcurrently :: Rec el Concurrently [Name, Email Work]bobConcurrently = Concurrently $ fetchBob
concurrentBob :: IO (PlainRec el [Name, Email Work])concurrentBob = runConcurrently (rdist bobConcurrently)
Concurrent records with Async
newtype Concurrently a= Concurrently { runConcurrently :: IO a }
( $ ) :: (∀ a. f a→ g a)→ Rec el f rs→ Rec el g rs
bobConcurrently :: Rec el Concurrently [Name, Email Work]bobConcurrently = Concurrently $ fetchBob
concurrentBob :: IO (PlainRec el [Name, Email Work])concurrentBob = runConcurrently (rdist bobConcurrently)
Concurrent records with Async
newtype Concurrently a= Concurrently { runConcurrently :: IO a }
( $ ) :: (∀ a. f a→ g a)→ Rec el f rs→ Rec el g rs
bobConcurrently :: Rec el Concurrently [Name, Email Work]bobConcurrently = Concurrently $ fetchBob
concurrentBob :: IO (PlainRec el [Name, Email Work])concurrentBob = runConcurrently (rdist bobConcurrently)
Concurrent records with Async
newtype Concurrently a= Concurrently { runConcurrently :: IO a }
( $ ) :: (∀ a. f a→ g a)→ Rec el f rs→ Rec el g rs
bobConcurrently :: Rec el Concurrently [Name, Email Work]bobConcurrently = Concurrently $ fetchBob
concurrentBob :: IO (PlainRec el [Name, Email Work])concurrentBob = runConcurrently (rdist bobConcurrently)
Type Theoretic Semantics for Records
Universes a la Tarski
I A type U of codes for types.I Function ElU : U → Type.
Γ ` s : UΓ ` ElU(s) : Type
Universes a la Tarski
I A type U of codes for types.
I Function ElU : U → Type.
Γ ` s : UΓ ` ElU(s) : Type
Universes a la Tarski
I A type U of codes for types.I Function ElU : U → Type.
Γ ` s : UΓ ` ElU(s) : Type
Universes a la Tarski
I A type U of codes for types.I Function ElU : U → Type.
Γ ` s : UΓ ` ElU(s) : Type
Universes a la Tarski
Type
Universes a la Tarski
Type
Universes a la Tarski
Type
Universes a la Tarski
Type
Records as products
Records as products
Records: the product of the image of ElU in Typerestricted to a subset of U .
Records as products
Type
Records as products
Type
×× ×
×
Vinyl: beyond records?
Records and corecords are finite products and sumsrespectively.
Rec(ElU ;F ; rs) :≡∏U|rs
F ◦ ElU
CoRec(ElU ;F ; rs) :≡∑U|rs
F ◦ ElU
Data(ElU ;F ; rs) :≡WU|rs
F ◦ ElU
Codata(ElU ;F ; rs) :≡MU|rs
F ◦ ElU
Vinyl: beyond records?
Records and corecords are finite products and sumsrespectively.
Rec(ElU ;F ; rs) :≡∏U|rs
F ◦ ElU
CoRec(ElU ;F ; rs) :≡∑U|rs
F ◦ ElU
Data(ElU ;F ; rs) :≡WU|rs
F ◦ ElU
Codata(ElU ;F ; rs) :≡MU|rs
F ◦ ElU
Vinyl: beyond records?
Records and corecords are finite products and sumsrespectively.
Rec(ElU ;F ; rs) :≡∏U|rs
F ◦ ElU
CoRec(ElU ;F ; rs) :≡∑U|rs
F ◦ ElU
Data(ElU ;F ; rs) :≡WU|rs
F ◦ ElU
Codata(ElU ;F ; rs) :≡MU|rs
F ◦ ElU
Vinyl: beyond records?
Records and corecords are finite products and sumsrespectively.
Rec(ElU ;F ; rs) :≡∏U|rs
F ◦ ElU
CoRec(ElU ;F ; rs) :≡∑U|rs
F ◦ ElU
Data(ElU ;F ; rs) :≡WU|rs
F ◦ ElU
Codata(ElU ;F ; rs) :≡MU|rs
F ◦ ElU
Vinyl: beyond records?
Records and corecords are finite products and sumsrespectively.
Rec(ElU ;F ; rs) :≡∏U|rs
F ◦ ElU
CoRec(ElU ;F ; rs) :≡∑U|rs
F ◦ ElU
Data(ElU ;F ; rs) :≡WU|rs
F ◦ ElU
Codata(ElU ;F ; rs) :≡MU|rs
F ◦ ElU
Vinyl: beyond records?
Records and corecords are finite products and sumsrespectively.
Rec(ElU ;F ; rs) :≡∏U|rs
F ◦ ElU
CoRec(ElU ;F ; rs) :≡∑U|rs
F ◦ ElU
Data(ElU ;F ; rs) :≡WU|rs
F ◦ ElU
Codata(ElU ;F ; rs) :≡MU|rs
F ◦ ElU
Vinyl: beyond records?
(U|rs) / (F ◦ ElU)
Vinyl: beyond records?
J(U|rs) / (F ◦ ElU)KΠ
Vinyl: beyond records?
J(U|rs) / (F ◦ ElU)KW
Vinyl: beyond records?
J(U|rs) / (F ◦ ElU)KM
Presheaves
A presheaf on some space X is a functorO(X)op → Type, where O is the category of open sets ofX for whatever topology you have chosen.
Presheaves
A presheaf on some space X is a functorO(X)op → Type, where O is the category of open sets ofX for whatever topology you have chosen.
Topologies on some space X
I What are the open sets on X?I The empty set and X are open setsI The union of open sets is openI Finite intersections of open sets are open
Topologies on some space X
I What are the open sets on X?
I The empty set and X are open setsI The union of open sets is openI Finite intersections of open sets are open
Topologies on some space X
I What are the open sets on X?I The empty set and X are open sets
I The union of open sets is openI Finite intersections of open sets are open
Topologies on some space X
I What are the open sets on X?I The empty set and X are open setsI The union of open sets is open
I Finite intersections of open sets are open
Topologies on some space X
I What are the open sets on X?I The empty set and X are open setsI The union of open sets is openI Finite intersections of open sets are open
Records are presheaves
I Let O = P, the discrete topologyI Then records on a universe X give rise to a presheafR: subset inclusions are taken to casts from larger tosmaller records
for U ∈ P(X) R(U) :≡∏U
ElX |U : Type
for i : V ↪→ U R(i) :≡ cast : R(U)→ R(V )
Records are presheaves
I Let O = P, the discrete topology
I Then records on a universe X give rise to a presheafR: subset inclusions are taken to casts from larger tosmaller records
for U ∈ P(X) R(U) :≡∏U
ElX |U : Type
for i : V ↪→ U R(i) :≡ cast : R(U)→ R(V )
Records are presheaves
I Let O = P, the discrete topologyI Then records on a universe X give rise to a presheafR: subset inclusions are taken to casts from larger tosmaller records
for U ∈ P(X) R(U) :≡∏U
ElX |U : Type
for i : V ↪→ U R(i) :≡ cast : R(U)→ R(V )
Records are presheaves
I Let O = P, the discrete topologyI Then records on a universe X give rise to a presheafR: subset inclusions are taken to casts from larger tosmaller records
for U ∈ P(X) R(U) :≡∏U
ElX |U : Type
for i : V ↪→ U R(i) :≡ cast : R(U)→ R(V )
Records are presheaves
I Let O = P, the discrete topologyI Then records on a universe X give rise to a presheafR: subset inclusions are taken to casts from larger tosmaller records
for U ∈ P(X) R(U) :≡∏U
ElX |U : Type
for i : V ↪→ U R(i) :≡ cast : R(U)→ R(V )
Records are sheaves
For a cover U =⋃
i Ui on X, then:
e = λr.λi. castUi(r)
p = λf.λi.λj. castUi∩Uj(f(i))
q = λf.λi.λj. castUi∩Uj(f(j))
Records are sheaves
For a cover U =⋃
i Ui on X, then:
R(U)∏
iR(Ui)∏
i,jR(Ui ∩ Uj)e p
q
is an equalizer, where
e = λr.λi. castUi(r)
p = λf.λi.λj. castUi∩Uj(f(i))
q = λf.λi.λj. castUi∩Uj(f(j))
Records are sheavesFor a cover U =
⋃i Ui on X, then:
R(U)∏
iR(Ui)∏
i,jR(Ui ∩ Uj)
Γ
e
m!u
p
q
where
e = λr.λi. castUi(r)
p = λf.λi.λj. castUi∩Uj(f(i))
q = λf.λi.λj. castUi∩Uj(f(j))
Records with non-trivial topology
NameType :≡ {F,M,L}A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[`] | ` ∈ Label}
ElA :≡ λ .String
T :≡ {U ∈ P(A) | Name[M ] ∈ U⇒ {Name[F ],Name[L]} ⊆ U}
ex : RT ({Name[t] | t ∈ NameType})ex :≡ {Name[F ] 7→ ”Robert”;
Name[M ] 7→ ”W”;Name[L] 7→ ”Harper”}
nope : RT ({Name[M ],Phone[Work]})nope :≡ {Name[M ] 7→ ”W”;
Phone[Work] 7→ ”5555555555”}
Records with non-trivial topology
NameType :≡ {F,M,L}
A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[`] | ` ∈ Label}ElA :≡ λ .String
T :≡ {U ∈ P(A) | Name[M ] ∈ U⇒ {Name[F ],Name[L]} ⊆ U}
ex : RT ({Name[t] | t ∈ NameType})ex :≡ {Name[F ] 7→ ”Robert”;
Name[M ] 7→ ”W”;Name[L] 7→ ”Harper”}
nope : RT ({Name[M ],Phone[Work]})nope :≡ {Name[M ] 7→ ”W”;
Phone[Work] 7→ ”5555555555”}
Records with non-trivial topology
NameType :≡ {F,M,L}A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[`] | ` ∈ Label}
ElA :≡ λ .String
T :≡ {U ∈ P(A) | Name[M ] ∈ U⇒ {Name[F ],Name[L]} ⊆ U}
ex : RT ({Name[t] | t ∈ NameType})ex :≡ {Name[F ] 7→ ”Robert”;
Name[M ] 7→ ”W”;Name[L] 7→ ”Harper”}
nope : RT ({Name[M ],Phone[Work]})nope :≡ {Name[M ] 7→ ”W”;
Phone[Work] 7→ ”5555555555”}
Records with non-trivial topology
NameType :≡ {F,M,L}A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[`] | ` ∈ Label}
ElA :≡ λ .String
T :≡ {U ∈ P(A) | Name[M ] ∈ U⇒ {Name[F ],Name[L]} ⊆ U}
ex : RT ({Name[t] | t ∈ NameType})ex :≡ {Name[F ] 7→ ”Robert”;
Name[M ] 7→ ”W”;Name[L] 7→ ”Harper”}
nope : RT ({Name[M ],Phone[Work]})nope :≡ {Name[M ] 7→ ”W”;
Phone[Work] 7→ ”5555555555”}
Records with non-trivial topology
NameType :≡ {F,M,L}A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[`] | ` ∈ Label}
ElA :≡ λ .String
T :≡ {U ∈ P(A) | Name[M ] ∈ U⇒ {Name[F ],Name[L]} ⊆ U}
ex : RT ({Name[t] | t ∈ NameType})ex :≡ {Name[F ] 7→ ”Robert”;
Name[M ] 7→ ”W”;Name[L] 7→ ”Harper”}
nope : RT ({Name[M ],Phone[Work]})nope :≡ {Name[M ] 7→ ”W”;
Phone[Work] 7→ ”5555555555”}
Records with non-trivial topology
NameType :≡ {F,M,L}A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[`] | ` ∈ Label}
ElA :≡ λ .String
T :≡ {U ∈ P(A) | Name[M ] ∈ U⇒ {Name[F ],Name[L]} ⊆ U}
ex : RT ({Name[t] | t ∈ NameType})ex :≡ {Name[F ] 7→ ”Robert”;
Name[M ] 7→ ”W”;Name[L] 7→ ”Harper”}
nope : RT ({Name[M ],Phone[Work]})nope :≡ {Name[M ] 7→ ”W”;
Phone[Work] 7→ ”5555555555”}
Records with non-trivial topology
NameType :≡ {F,M,L}A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[`] | ` ∈ Label}
ElA :≡ λ .String
T :≡ {U ∈ P(A) | Name[M ] ∈ U⇒ {Name[F ],Name[L]} ⊆ U}
ex : RT ({Name[t] | t ∈ NameType})ex :≡ {Name[F ] 7→ ”Robert”;
Name[M ] 7→ ”W”;Name[L] 7→ ”Harper”}
nope : RT ({Name[M ],Phone[Work]})nope :≡ {Name[M ] 7→ ”W”;
Phone[Work] 7→ ”5555555555”}
Future work
I Complete: formalization of records with topologies aspresheaves in Coq
I In Progress: formalization of records as sheavesI Future: extension to dependent records using
extensional type theory and realizability (Nuprl,MetaPRL)
Future work
I Complete: formalization of records with topologies aspresheaves in Coq
I In Progress: formalization of records as sheavesI Future: extension to dependent records using
extensional type theory and realizability (Nuprl,MetaPRL)
Future work
I Complete: formalization of records with topologies aspresheaves in Coq
I In Progress: formalization of records as sheaves
I Future: extension to dependent records usingextensional type theory and realizability (Nuprl,MetaPRL)
Future work
I Complete: formalization of records with topologies aspresheaves in Coq
I In Progress: formalization of records as sheavesI Future: extension to dependent records using
extensional type theory and realizability (Nuprl,MetaPRL)
Questions