Questo non è forse l'approccio più sana, ma possiamo abusare del mio pacchetto reflection
a mentire su 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)
Dato che ora possiamo sbirciare la TypeRep
del nostro ragionamento Dynamic
e istanziare la nostra funzione Dynamic
in modo appropriato.
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()))
potrebbe essere molto più facile se base
qualcosa solo fornito come apD
per noi, ma che richiede un rango 2 tipo, e Typeable
/Dynamic
riesce ad evitarli, anche se Data
non lo fa.
Un altro percorso sarebbe quello di solo sfruttare l'attuazione di Dynamic
:
data Dynamic = Dynamic TypeRep Any
e unsafeCoerce
per il proprio tipo di dati Dynamic'
, fare ciò che è necessario fare con il TypeRep
negli interni, e dopo l'applicazione la funzione , unsafeCoerce
tutto indietro.
fonte
2012-06-05 01:16:42
Sembra che "polytypeable" e "polytypeable-utils' possano essere utilizzati per questo, anche se dovresti ancora implementare l'unificazione completa, nel peggiore dei casi. – Carl