haskell - Cómo aplicar una función polimórfica a un valor dinámico
types dynamic-typing (1)
¿Existe una forma sensata de aplicar una función polimórfica a un valor de tipo Dynamic
?
Por ejemplo, tengo un valor de tipo Dynamic
y quiero aplicar Just
al valor dentro de la Dynamic
. Entonces, si el valor fue construido por toDyn True
, quiero que el resultado sea toDyn (Just True)
. La cantidad de tipos diferentes que pueden ocurrir dentro de la Dynamic
no está limitada.
(Tengo una solución cuando los tipos involucrados provienen de un universo cerrado, pero es desagradable).
Quizás este no sea el enfoque más sensato, pero podemos abusar de mi paquete de reflection
para mentir sobre un 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)
Dado que ahora podemos echar un vistazo al TypeRep
de nuestro argumento Dynamic
y crear una instancia de nuestra función Dynamic
manera adecuada.
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 ()))
Podría ser mucho más fácil si la base
simplemente nos proporcionara algo como apD
para nosotros, pero eso requiere un tipo de rango 2, y Typeable
/ Dynamic
puede evitarlos, incluso si Data
no lo hace.
Otra ruta sería simplemente explotar la implementación de Dynamic
:
data Dynamic = Dynamic TypeRep Any
y unsafeCoerce
a su propio tipo de datos Dynamic''
, haga lo que necesita hacer con el TypeRep
en las TypeRep
internas y, después de aplicar su función, unsafeCoerce
todo lo anterior.