2021-01-07 07:26:30 +00:00
# Purescript-Typeable
Reified types for Purescript
This is an implementation of indexed typereps for Purescript, similar to the [corresponding implementation in Haskell ](https://hackage.haskell.org/package/base-4.10.0.0/docs/Type-Reflection.html#t:TypeRep ).
2021-01-18 11:30:44 +00:00
[Slides for a talk about Purescript-Typeable ](https://speakerdeck.com/ajnsit/purescript-typeable ), presented at the Purescript semi-monthly meetup on 18 January 2021, are available.
2021-01-10 21:46:31 +00:00
## Data.Typeable
2021-01-07 07:26:30 +00:00
`TypeReps` are values that represent types (i.e. they reify types). When they are *indexed* they have the type itself as a parameter.
```purescript
data TypeRep a -- A *value* that represents the type 'a'
```
All typeable things have typereps -
```purescript
class Typeable a where
typeRep :: TypeRep a
```
Instances are provided for common data types.
We can recover the unindexed representation by making it existential -
```purescript
data SomeTypeRep = SomeTypeRep (Exists TypeRep)
```
We can also test typereps for equality -
```purescript
eqTypeRep :: forall a b. TypeRep a -> TypeRep b -> Boolean
```
2021-01-10 21:46:31 +00:00
We can compare two typeReps and extract a witness for type equality.
2021-01-07 07:26:30 +00:00
```purescript
2021-01-10 21:46:31 +00:00
eqT :: forall a b. TypeRep a -> TypeRep b -> Maybe (a ~ b)
2021-01-07 07:26:30 +00:00
```
2021-01-10 21:46:31 +00:00
## Data.Dynamic
We can have dynamic values which holds a value `a` in a context `t` and forgets the type of `a`
2021-01-07 07:26:30 +00:00
```purescript
2021-01-10 21:46:31 +00:00
data Dynamic t
2021-01-07 07:26:30 +00:00
```
2021-01-10 21:46:31 +00:00
We can wrap a value into a dynamic
2021-01-07 07:26:30 +00:00
```purescript
2021-01-10 21:46:31 +00:00
-- Wrap a value into a dynamic
dynamic :: forall a t. Typeable a => t a -> Dynamic t
2021-01-07 07:26:30 +00:00
```
2021-04-22 10:45:38 +00:00
We can recover the value from a dynamic if supply the type we expect to find in the Dynamic
2021-01-07 07:26:30 +00:00
```purescript
2021-01-10 21:46:31 +00:00
unwrapDynamic :: forall a. TypeRep a -> Dynamic t -> Maybe a
2021-01-07 07:26:30 +00:00
```
## Deriving `Typeable` for custom data types
2021-04-22 10:45:38 +00:00
It's extremely easy. You just need to create a mechanical `TagT` class instance for your datatype.
2021-01-07 07:26:30 +00:00
2021-04-22 10:45:38 +00:00
For example -
2021-01-07 07:26:30 +00:00
```purescript
data Person = Person {name::String, age::Int}
2021-04-22 10:45:38 +00:00
instance tagTPerson :: TagT Person where tagT = proxyT
2021-01-07 07:26:30 +00:00
```
2021-04-22 10:45:38 +00:00
This is valid even for data types that take parameters. For example -
2021-01-07 07:26:30 +00:00
```purescript
data Optional a = Some a | None
2021-04-22 10:45:38 +00:00
instance tagTOptional :: TagT Optional where tagT = proxyT
2021-01-07 07:26:30 +00:00
```
2021-01-10 21:46:31 +00:00
**Don't worry about getting it wrong since the type system will prevent you from writing an invalid instance.**
2021-01-07 07:26:30 +00:00
2021-01-10 21:46:31 +00:00
> #### CAVEAT
2021-04-22 10:45:38 +00:00
> *Do not add any extra constraints to the instances*. For example don't do `Foo => TagT Person`. This currently cannot be caught by the type checker, but will break typerep comparisons for your data type.
2021-01-07 07:26:30 +00:00
2021-01-10 21:46:31 +00:00
And that's it! You are done! Now your datatype will have a `Typeable` instance.
2021-04-22 10:45:38 +00:00
Note that you will have typeable instances even for unsaturated types. For example, with the `tagTOptional` instance above, you have instances for `TypeRep (Optional a)` as well as for `TypeRep Optional` .