Successfully reported this slideshow.
Upcoming SlideShare
×

of

Upcoming SlideShare
Phone Apps... para el teléfono de escritorio
Next

4

Share

# Galois Tech Talk / Vinyl: Records in Haskell and Type Theory

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.

See all

See all

### Galois Tech Talk / Vinyl: Records in Haskell and Type Theory

1. 1. Vinyl: Records in Haskell and Type Theory Jon Sterling jonmsterling.com August 12, 2014
2. 2. Records in GHC 7.8
3. 3. Records in GHC 7.8 Haskell records are nominally typed
4. 4. Records in GHC 7.8 Haskell records are nominally typed They may not share ﬁeld names
5. 5. Records in GHC 7.8 Haskell records are nominally typed They may not share ﬁeld names data R = R { x :: X }
6. 6. Records in GHC 7.8 Haskell records are nominally typed They may not share ﬁeld names data R = R { x :: X } data R’ = R’ { x :: X } −− ˆ Error
7. 7. Structural typing
8. 8. Structural typing Sharing ﬁeld names and accessors
9. 9. Structural typing Sharing ﬁeld names and accessors Record types may be characterized structurally
10. 10. Row polymorphism
11. 11. Row polymorphism How do we express the type of a function which adds a ﬁeld to a record?
12. 12. Row polymorphism How do we express the type of a function which adds a ﬁeld to a record? x : {foo : A} f(x) : {foo : A, bar : B}
13. 13. Row polymorphism How do we express the type of a function which adds a ﬁeld to a record? x : {foo : A; rs} f(x) : {foo : A, bar : B; rs}
15. 15. Roll your own in Haskell data (s :: Symbol) ::: (t :: ∗) = Field
16. 16. Roll your own in Haskell data (s :: Symbol) ::: (t :: ∗) = Field data Rec :: [∗] → ∗ where
17. 17. Roll your own in Haskell data (s :: Symbol) ::: (t :: ∗) = Field data Rec :: [∗] → ∗ where RNil :: Rec ’[]
18. 18. Roll your own in Haskell data (s :: Symbol) ::: (t :: ∗) = Field data Rec :: [∗] → ∗ where RNil :: Rec ’[] (:&) :: !t → !(Rec rs) → Rec ((s ::: t) ’: rs)
19. 19. 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 :: [∗])
20. 20. 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
21. 21. 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]
22. 22. 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)
23. 23. 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
25. 25. Roll your own in Haskell f :: Rec (”foo” ::: A ’: rs) → Rec (”bar” ::: B ’: ”foo” ::: A ’: rs)
26. 26. Why be stringly typed?
27. 27. Why be stringly typed? Let’s generalize our key space
28. 28. Old We relied on a single representation for keys as pairs of strings and types. data Rec :: [∗] → ∗ where RNil :: Rec ’[] (:&) :: !t → !(Rec rs) → Rec ((s ::: t) ’: rs)
29. 29. Proposed We put the keys in an arbitrary type (kind) and describe their semantics with a function el (for elements). data Rec :: [∗] → ∗ where RNil :: Rec ’[] (:&) :: !t → !(Rec rs) → Rec ((s ::: t) ’: rs)
30. 30. Proposed We put the keys in an arbitrary type (kind) and describe their semantics with a function el (for elements). data Rec :: (el :: k → ∗) → (rs :: [k]) → ∗ where RNil :: Rec el ’[] (:&) :: ∀(r :: k) (rs’:: [k]). !(el r) → !(Rec el rs) → Rec (r ’: rs’)
31. 31. Proposed We put the keys in an arbitrary type (kind) and describe their semantics with a function el (for elements). data Rec :: (k → ∗) → [k] → ∗ where RNil :: Rec el ’[] (:&) :: !(el r) → !(Rec el rs) → Rec (r ’: rs)
32. 32. Actual Type families are not functions, but in many cases can simulate them using Richard Eisenberg’s technique outlined in Defunctionalization for the win. data TyFun :: ∗ → ∗ → ∗
33. 33. Actual Type families are not functions, but in many cases can simulate them using Richard Eisenberg’s technique outlined in Defunctionalization for the win. data TyFun :: ∗ → ∗ → ∗ type family (f :: TyFun k l → ∗) \$ (x :: k) :: l
34. 34. Actual Type families are not functions, but in many cases can simulate them using Richard Eisenberg’s technique outlined in Defunctionalization for the win. data TyFun :: ∗ → ∗ → ∗ type family (f :: TyFun k l → ∗) \$ (x :: k) :: l data Rec :: (TyFun k ∗ → ∗) → [k] → ∗ where RNil :: Rec el ’[] (:&) :: !(el \$ r) → !(Rec el rs) → Rec el (r ’: rs)
35. 35. Example data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label
36. 36. Example data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label data SLabel :: Label → ∗ where SHome :: SLabel Home SWork :: SLabel Work
37. 37. Example data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label data SLabel :: Label → ∗
38. 38. Example data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label data SLabel :: Label → ∗ data SAddrKeys :: AddrKeys → ∗ where SName :: SAddrKeys Name SPhone :: SLabel l → SAddrKeys (Phone l) SEmail :: SLabel l → SAddrKeys (Email l)
39. 39. Example data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label data SLabel :: Label → ∗ data SAddrKeys :: AddrKeys → ∗
40. 40. Example data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label data SLabel :: Label → ∗ data SAddrKeys :: AddrKeys → ∗ data ElAddr :: (TyFun AddrKeys ∗) → ∗ where ElAddr :: ElAddr el
42. 42. Sugared example import Data.Singletons as S
43. 43. Sugared example import Data.Singletons as S data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label S.genSingletons [ ’’Label, ’’AddrKeys ]
44. 44. Sugared example import Data.Singletons as S data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label S.genSingletons [ ’’Label, ’’AddrKeys ] makeUniverse ’’AddrKeys ”ElAddr”
45. 45. Sugared example import Data.Singletons as S data Label = Home | Work data AddrKeys = Name | Phone Label | Email Label S.genSingletons [ ’’Label, ’’AddrKeys ] makeUniverse ’’AddrKeys ”ElAddr” type instance ElAddr \$ Name = String type instance ElAddr \$ (Phone l) = [N] type instance ElAddr \$ (Email l) = String type AddrRec rs = Rec ElAddr rs
46. 46. Example records bob :: AddrRec [Name, Email Work] bob = SName =: ”Robert W. Harper” ⊕ SEmail SWork =: ”rwh@cs.cmu.edu”
47. 47. Example records bob :: AddrRec [Name, Email Work] bob = SName =: ”Robert W. Harper” ⊕ SEmail SWork =: ”rwh@cs.cmu.edu” jon :: AddrRec [Name, Email Work, Email Home] jon = SName =: ”Jon M. Sterling” ⊕ SEmail SWork =: ”jon@fobo.net” ⊕ SEmail SHome =: ”jon@jonmsterling.com”
48. 48. Recovering HList
49. 49. Recovering HList data Id :: (TyFun k k) → ∗ where type instance Id \$ x = x
50. 50. Recovering HList data Id :: (TyFun k k) → ∗ where type instance Id \$ x = x type HList rs = Rec Id rs
51. 51. Recovering HList data Id :: (TyFun k k) → ∗ where type instance Id \$ x = x type HList rs = Rec Id rs ex :: HList [Z, Bool, String] ex = 34 :& True :& ”vinyl” :& RNil
52. 52. Validating records validateName :: String → Either Error String validateEmail :: String → Either Error String validatePhone :: [N] → Either Error [N]
53. 53. Validating records validateName :: String → Either Error String validateEmail :: String → Either Error String validatePhone :: [N] → Either Error [N] *unnnnnhhh...*
54. 54. Validating records validateName :: String → Either Error String validateEmail :: String → Either Error String validatePhone :: [N] → Either Error [N] *unnnnnhhh...* validateContact :: AddrRec [Name, Email Work] → Either Error (AddrRec [Name, Email Work])
55. 55. Welp.
56. 56. Effects inside records data Rec :: (TyFun k ∗ → ∗) → [k] → ∗ where RNil :: Rec el ’[] (:&) :: !(el \$ r) → !(Rec el rs) → Rec el (r ’: rs)
57. 57. Effects inside records data Rec :: (TyFun k ∗ → ∗) → (∗ → ∗) → [k] → ∗ where RNil :: Rec el f ’[] (:&) :: !(f (el \$ r)) → !(Rec el f rs) → Rec el f (r ’: rs)
58. 58. Effects inside records data Rec :: (TyFun k ∗ → ∗) → (∗ → ∗) → [k] → ∗ where RNil :: Rec el f ’[] (:&) :: !(f (el \$ r)) → !(Rec el f rs) → Rec el f (r ’: rs)
59. 59. Effects inside records data Rec :: (TyFun k ∗ → ∗) → (∗ → ∗) → [k] → ∗ where RNil :: 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
60. 60. Effects inside records data Rec :: (TyFun k ∗ → ∗) → (∗ → ∗) → [k] → ∗ where RNil :: 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
61. 61. Compositional validation type Validator a = a → Either Error a
62. 62. Compositional validation newtype Lift o f g x = Lift { runLift :: f x ‘o‘ g x } type Validator = Lift (→) Identity (Either Error)
63. 63. Compositional validation newtype Lift o f g x = Lift { runLift :: f x ‘o‘ g x } type Validator = Lift (→) Identity (Either Error)
64. 64. 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]
65. 65. 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 ]
66. 66. 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 TotalContact validateContact = validateName ⊕ validateEmail ⊕ validateEmail ⊕ validatePhone ⊕ validatePhone
67. 67. Record effect operators
68. 68. Record effect operators ( ) :: Rec el (Lift (→) f g) rs → Rec el f rs → Rec el g rs
69. 69. 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)
70. 70. 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)
71. 71. Compositional validation bob :: AddrRec [Name, Email Work] validateContact :: AddrRec Validator TotalContact
72. 72. Compositional validation bob :: AddrRec [Name, Email Work] validateContact :: AddrRec Validator TotalContact bobValid :: AddrRec (Either Error) [Name, Email Work] bobValid = cast validateContact bob
73. 73. 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
74. 74. Laziness as an effect
75. 75. Laziness as an effect newtype Identity a = Identity { runIdentity :: a } data Thunk a = Thunk { unThunk :: a }
76. 76. Laziness as an effect newtype Identity a = Identity { runIdentity :: a } data Thunk a = Thunk { unThunk :: a } type PlainRec el rs = Rec el Identity rs
77. 77. 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
78. 78. Concurrent records with Async
79. 79. Concurrent records with Async fetchName :: AddrRec IO ’[Name] fetchName = SName ⇐ runDB nameQuery
80. 80. Concurrent records with Async fetchName :: AddrRec IO ’[Name] fetchName = SName ⇐ runDB nameQuery fetchWorkEmail :: AddrRec IO ’[Email Work] fetchWorkEmail = SEmail SWork ⇐ runDB emailQuery
81. 81. 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
82. 82. Concurrent records with Async
83. 83. Concurrent records with Async newtype Concurrently a = Concurrently { runConcurrently :: IO a }
84. 84. Concurrent records with Async newtype Concurrently a = Concurrently { runConcurrently :: IO a } ( \$ ) :: (∀ a. f a → g a) → Rec el f rs → Rec el g rs
85. 85. 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
86. 86. 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)
87. 87. Type Theoretic Semantics for Records
88. 88. Universes `a la Tarski
89. 89. Universes `a la Tarski A type U of codes for types.
90. 90. Universes `a la Tarski A type U of codes for types. Function ElU : U → Type.
91. 91. Universes `a la Tarski A type U of codes for types. Function ElU : U → Type. Γ s : U Γ ElU (s) : Type
92. 92. Universes `a la Tarski Type
93. 93. Universes `a la Tarski  Type
94. 94. Universes `a la Tarski  Type
95. 95. Universes `a la Tarski  Type
96. 96. Records as products
97. 97. Records as products Records: the product of the image of ElU in Type restricted to a subset of U.
98. 98. Records as products  Type
99. 99. Records as products  Type × × × ×
100. 100. Vinyl: beyond records?
101. 101. Vinyl: beyond records? Records and corecords are ﬁnite products and sums respectively.
102. 102. Vinyl: beyond records? Records and corecords are ﬁnite products and sums respectively. Rec(ElU ; F; rs) :≡ U|rs F ◦ ElU
103. 103. Vinyl: beyond records? Records and corecords are ﬁnite products and sums respectively. Rec(ElU ; F; rs) :≡ U|rs F ◦ ElU CoRec(ElU ; F; rs) :≡ U|rs F ◦ ElU
104. 104. Vinyl: beyond records? Records and corecords are ﬁnite products and sums respectively. Rec(ElU ; F; rs) :≡ U|rs F ◦ ElU CoRec(ElU ; F; rs) :≡ U|rs F ◦ ElU Data(ElU ; F; rs) :≡ WU|rs F ◦ ElU
105. 105. Vinyl: beyond records? Records and corecords are ﬁnite products and sums respectively. 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
106. 106. Vinyl: beyond records? (U|rs) (F ◦ ElU )
107. 107. Vinyl: beyond records? (U|rs) (F ◦ ElU ) Π
108. 108. Vinyl: beyond records? (U|rs) (F ◦ ElU ) W
109. 109. Vinyl: beyond records? (U|rs) (F ◦ ElU ) M
110. 110. Presheaves
111. 111. Presheaves A presheaf on some space X is a functor O(X)op → Type, where O is the category of open sets of X for whatever topology you have chosen.
112. 112. Topologies on some space X
113. 113. Topologies on some space X What are the open sets on X?
114. 114. Topologies on some space X What are the open sets on X? The empty set and X are open sets
115. 115. Topologies on some space X What are the open sets on X? The empty set and X are open sets The union of open sets is open
116. 116. Topologies on some space X What are the open sets on X? The empty set and X are open sets The union of open sets is open Finite intersections of open sets are open
117. 117. Records are presheaves
118. 118. Records are presheaves Let O = P, the discrete topology
119. 119. Records are presheaves Let O = P, the discrete topology Then records on a universe X give rise to a presheaf R: subset inclusions are taken to casts from larger to smaller records
120. 120. Records are presheaves Let O = P, the discrete topology Then records on a universe X give rise to a presheaf R: subset inclusions are taken to casts from larger to smaller records for U ∈ P(X) R(U) :≡ U ElX|U : Type
121. 121. Records are presheaves Let O = P, the discrete topology Then records on a universe X give rise to a presheaf R: subset inclusions are taken to casts from larger to smaller records for U ∈ P(X) R(U) :≡ U ElX|U : Type for i : V → U R(i) :≡ cast : R(U) → R(V )
122. 122. Records are sheaves
123. 123. Records are sheaves For a cover U = i Ui on X, then: R(U) i R(Ui) i,j R(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))
124. 124. Records are sheaves For a cover U = i Ui on X, then: R(U) i R(Ui) i,j R(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))
125. 125. Records with non-trivial topology
126. 126. Records with non-trivial topology NameType :≡ {F, M, L}
127. 127. Records with non-trivial topology NameType :≡ {F, M, L} A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[ ] | ∈ Label}
128. 128. Records with non-trivial topology NameType :≡ {F, M, L} A :≡ {Name[t] | t ∈ NameType} ∪ {Phone[ ] | ∈ Label} ElA :≡ λ .String
129. 129. 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}
130. 130. 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] → ”Robert”; Name[M] → ”W”; Name[L] → ”Harper”}
131. 131. 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] → ”Robert”; Name[M] → ”W”; Name[L] → ”Harper”} nope : RT ({Name[M], Phone[Work]}) nope :≡ {Name[M] → ”W”; Phone[Work] → ”5555555555”}
132. 132. Future work
133. 133. Future work Complete: formalization of records with topologies as presheaves in Coq
134. 134. Future work Complete: formalization of records with topologies as presheaves in Coq In Progress: formalization of records as sheaves
135. 135. Future work Complete: formalization of records with topologies as presheaves in Coq In Progress: formalization of records as sheaves Future: extension to dependent records using extensional type theory and realizability (Nuprl, MetaPRL)
136. 136. Questions
• #### yanana

Dec. 3, 2015

Apr. 21, 2015

Apr. 4, 2015
• #### manojkumrm

Aug. 12, 2014

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.

Total views

2,178

On Slideshare

0

From embeds

0

Number of embeds

89

18

Shares

0