This is an implementation of indexed typereps for Purescript, similar to the [corresponding implementation in Haskell](https://hackage.haskell.org/package/base/docs/Type-Reflection.html#t:TypeRep).
[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.
It's extremely easy. You just need to create a mechanical `Taggable` class instance for your datatype. The instance will always use the provided `makeTag` function. There is no other possible way to create an instance.
**Don't worry about getting it wrong since the type system will prevent you from writing an invalid instance.**
> #### CAVEAT
> *Do not add any extra constraints to the instances*. For example don't do `Foo => Taggable Person`. This currently cannot be caught by the type checker, but will break typerep comparisons for your data type.
And that's it! You are done! Now your datatype will have a `Typeable` instance.
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`.
This is an implementation of the Data class Purescript, similar to the [corresponding implementation of Data in Haskell](https://hackage.haskell.org/package/base/docs/Data-Data.html). Check the documentation there for more information on the API. A brief overview is provided below.
Where `DataDict` is a manually reified dictionary because PureScript has trouble with constraints inside records.
Common instances are provided for `Data`. You can define `Data` instances for your own datatypes though it is slightly involved due to the dictionary reification.
When you cut through the dictionary reification noise, the definition of `Data` looks like the following -
Simply handle the branches separately, for example -
```purescript
instance Data Foo where
dataDict = DataDict \k z foo -> case foo of
Bar b -> z Bar `k` b
Buzz i -> z Buzz `k` i
```
### Using Data.Data
Once you have a `Data` instance for your datatype, you can use `gmapT`, and functions that depend on `gmapT`, such as `everywhere`.
For example, to apply a function `f :: forall a. Typeable a => a -> a` to all leaves of your data structure, you can do `everywhere f`. Inside `f`, you can use the `Typeable` instance to decide when to change the data structure. For example, if you want the function to increment all integers, but leave all other data intact, use -
```purescript
f :: forall a. Typeable a => a -> a
f a =
-- Check if `a` is an int
case (typeRep :: _ a) `eqT` (typeRep :: _ Int) of
-- Return unmodified if `a` is not an int
Nothing -> a
Just witness -> do
-- If `a` is an int, we get access to bidirectional conversion functions