How to apply a polymorphic function to a Dynamic value

dynamic-typing, haskell, types

Solution

This is perhaps not the sanest approach, but we can abuse my `reflection` package to lie about a TypeRep.

{-# LANGUAGE Rank2Types, FlexibleContexts, ScopedTypeVariables #-}
import Data.Dynamic
import Data.Proxy
import Data.Reflection
import GHC.Prim (Any)
import Unsafe.Coerce

newtype WithRep s a = WithRep { withRep :: a }

instance Reifies s TypeRep => Typeable (WithRep s a) where
  typeOf s = reflect (Proxy :: Proxy s)

Given that we can now peek at the `TypeRep` of our `Dynamic` argument and instantiate our `Dynamic` function appropriately.

apD :: forall f. Typeable1 f => (forall a. a -> f a) -> Dynamic -> Dynamic
apD f a = dynApp df a
  where t = dynTypeRep a
        df = reify (mkFunTy t (typeOf1 (undefined :: f ()) `mkAppTy` t)) $ 
                  \(_ :: Proxy s) -> toDyn (WithRep f :: WithRep s (() -> f ()))

It could be a lot easier if `base` just supplied something like `apD` for us, but that requires a rank 2 type, and `Typeable`/`Dynamic` manage to avoid them, even if `Data` does not.

Another path would be to just exploit the implementation of `Dynamic`:

data Dynamic = Dynamic TypeRep Any

and `unsafeCoerce` to your own `Dynamic'` data type, do what you need to do with the `TypeRep` in the internals, and after applying your function, `unsafeCoerce` everything back.

Problem

Is there a sane way to apply a polymorphic function to a value of type `Dynamic`? For instance, I have a value of type `Dynamic` and I want to apply `Just` to the value inside the `Dynamic`. So if the value was constructed by `toDyn True` I want the result to be `toDyn (Just True)`. The number of different types that can occur inside the `Dynamic` is not bounded. (I have a solution when the types involved come from a closed universe, but it's unpleasant.)

Original source