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.)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With