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.)