2012-06-04 15 views
19

Esiste un modo corretto per applicare una funzione polimorfica a un valore di tipo Dynamic?Come applicare una funzione polimorfica a un valore dinamico

Ad esempio, ho un valore di tipo Dynamic e voglio applicare Just al valore all'interno dello Dynamic. Quindi, se il valore è stato creato da toDyn True, voglio che il risultato sia toDyn (Just True). Il numero di diversi tipi che possono verificarsi all'interno di Dynamic non è limitato.

(ho una soluzione in cui i tipi coinvolte provengono da un universo chiuso, ma è sgradevole.)

+0

Sembra che "polytypeable" e "polytypeable-utils' possano essere utilizzati per questo, anche se dovresti ancora implementare l'unificazione completa, nel peggiore dei casi. – Carl

risposta

15

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.

+2

Trovarsi a proposito di 'TypeRep' è ingegnoso, quindi accetterò questa risposta (usando' unsafeCoerce' per sbirciare e colpire all'interno di 'Dynamic' non si può definire saggia). – augustss

+0

@augusts: dov'è la differenza morale? –

+1

@AndreasRossberg È molto piccolo. :) Ma il primo è un po 'più robusto. Ad esempio, se l'implementazione di 'Dynamic' cambia in modo che i campi' TypeRep' e 'Any' cambino posto, il primo funzionerà ancora mentre quest'ultimo si arresta. – augustss