... | ... | @@ -59,6 +59,7 @@ newtype ctx :- c = Sub (ctx => Dict c) |
|
|
|
|
|
class (Binary a, Typeable a, Typeable (Ctx a)) => Serializable a where
|
|
|
type Ctx a :: Constraint
|
|
|
type Ctx a = ()
|
|
|
serializableDict :: StaticPtr (Ctx a :- Serializable a)
|
|
|
```
|
|
|
|
... | ... | @@ -67,7 +68,7 @@ class (Binary a, Typeable a, Typeable (Ctx a)) => Serializable a where |
|
|
|
|
|
In words, a *serializable value* is a value for which we have
|
|
|
a `Binary` instance and a `Typeable` instance, but moreover for which
|
|
|
we can obtain a `StaticPtr` referencing a *proof that the set of constraints `ctx` entails `Serializable a`*. (The `Dict` datatype and `(:-)` can be obtained from the [ constraints package](http://hackage.haskell.org/package/constraints) on Hackage). In other words, a value of type `ctx :- Serializable a` is *explicit* evidence that GHC's instance resolution can derive `Serializable a` from `ctx`. The constraint `ctx :=> Serializable a` is what allows reifying this evidence of instance resolution.
|
|
|
we can obtain a `StaticPtr` referencing a *proof that the set of constraints `Ctx a` entails `Serializable a`*. (The `Dict` datatype and `(:-)` can be obtained from the [ constraints package](http://hackage.haskell.org/package/constraints) on Hackage). In other words, a value of type `Ctx a :- Serializable a` is *explicit* evidence that GHC's instance resolution can derive `Serializable a` from `Ctx a`. The constraint `Ctx a :=> Serializable a` is what allows reifying this evidence of instance resolution.
|
|
|
|
|
|
|
|
|
One could make do with an empty class definition for `Serializable`, as is currently the case, but without this augmented definition, lifting arbitrary serializable values to `Closure`s becomes much less convenient (see `closurePure` below).
|
... | ... | @@ -80,7 +81,7 @@ class (Binary a, Typeable a, Typeable ctx) => Serializable ctx a | a -> ctx wher |
|
|
```
|
|
|
|
|
|
|
|
|
Most of the time, instance definitions have an empty context, meaning that one can very often take `Ctx a == ()`.
|
|
|
Most of the time, instance definitions have an empty context, meaning that one can very often take `Ctx a == ()` (this is a default, that must be overridden when necessary).
|
|
|
|
|
|
|
|
|
One might argue that `Serializable` is rather more complex than it could be. The central issue is that the `-XStaticPointers` extension alone does not offer any means to reify a constraint to *static* evidence in the form of a dictionary - a feature that is in general very useful indeed (see below). In principle this could be done, since dictionaries are morally either static, or simple combinations of static dictionaries, but it would require a further extension to the compiler, possibly to the type system itself. The above definition of `Serializable` comes at the economy of such a compiler extension.
|
... | ... | @@ -90,11 +91,9 @@ Below are some example instances: |
|
|
|
|
|
```wiki
|
|
|
instance Serializable Int where
|
|
|
type Ctx Int = ()
|
|
|
serializableDict = static (Sub Dict)
|
|
|
|
|
|
instance Serializable (Maybe Int) where
|
|
|
type Ctx (Maybe Int) = ()
|
|
|
serializableDict = static (Sub Dict)
|
|
|
|
|
|
instance Serializable b => Serializable (Either String b) where
|
... | ... | @@ -105,10 +104,31 @@ data Foo = Foo deriving (Generic, Typeable) |
|
|
|
|
|
instance Binary Foo
|
|
|
instance Serializable Foo where
|
|
|
type Ctx Foo = ()
|
|
|
serializableDict = static (Sub Dict)
|
|
|
```
|
|
|
|
|
|
|
|
|
If we define the following general instance in `distributed-closure`,
|
|
|
|
|
|
```wiki
|
|
|
instance (Serializable a, ctx ~ Ctx a) => ctx :=> Serializable a where
|
|
|
ins = unstatic serializableDict
|
|
|
```
|
|
|
|
|
|
|
|
|
we can slightly simplify all other instances, e.g.
|
|
|
|
|
|
```wiki
|
|
|
instance Serializable Foo where
|
|
|
serializableDict = static ins
|
|
|
```
|
|
|
|
|
|
|
|
|
Again, see the [ constraints package](http://hackage.haskell.org/package/constraints-0.4/docs/Data-Constraint.html) for the definition of the `(:=>)` type class.
|
|
|
|
|
|
|
|
|
Notice the pay-as-you-go nature of the instances. Only instances with polymorphic heads need an explicit definition for the `Ctx` type family. Most users do not have type parameterized data types that they want to serialize. Those users never need to learn about associated type families.
|
|
|
|
|
|
## Implementation
|
|
|
|
|
|
### Implementation in GHC
|
... | ... | |