2010-12-01 15 views
2

Donc Data.Map a dataCast2 défini, ce qui est logique, car il a un constructeur de type arité 2. Par défaut dataCast1const Nothing. dataCast2 est facilement défini comme gcast2.Data.Data - produisant dataCast1 pour un constructeur de type arity 2 (partiellement spécialisé)

Pour référence:

class Typeable a => Data a where 
    dataCast1 :: Typeable1 t => (forall d. Data d => c (t d)) -> Maybe (c a) 
    dataCast2 :: Typeable2 t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a) 
    ... 

gcast1 :: (Typeable1 t, Typeable1 t') => c (t a) -> Maybe (c (t' a)) 
gcast2 :: (Typeable2 t, Typeable2 t') => c (t a b) -> Maybe (c (t' a b)) 

La question posée est la suivante: tout donné dans Data.Data, Data.Typeable, etc., et donné un constructeur de type arité 2 pour lequel dataCast2 est défini (par exemple, Map ou (,)), est-il possible d'écrire une version de dataCast1 qui fait la bonne chose pour une spécialisation partielle de ce type constructeur, soit pour un constructeur spécifique à la fois, ou en général? Intuitivement, je pense qu'il devrait y avoir une bonne solution, mais mes premiers essais ont planté et brûlé.

+0

Cela ressemble à un problème intéressant, mais je pense que je vais avoir besoin d'un peu plus de fond. D'abord, une question. Que voulez-vous dire par «fait la bonne chose pour une application partielle de ce type de constructeur»? Les constructeurs de type peuvent apparaître partiellement appliqués dans la tête d'une déclaration de classe ou d'instance, cependant, partout ailleurs, ils doivent apparaître complètement appliqués AFAIK. –

+0

@Sean Bon point. Je l'ai changé pour lire "spécialisation partielle". Le point étant de pouvoir appeler 'myDataCast1' avec un résultat de' Maybe (c (Int, a)) 'de la même façon qu'on peut appeler' dataCast1' avec le résultat de 'Maybe (c (Maybe a))'. – sclv

Répondre

1

Je ne suis pas sûr si c'est ce que vous voulez, mais il pourrait vous orienter dans la bonne direction si ce n'est pas le cas. Il est écrit dans un style très similaire aux fonctions gcast, gcast1 et gcast2 de la bibliothèque Data.Typeable. Pour plus de détails, "lisez la source, Luke".

myDataCast1 :: forall c t d e a.(Typeable d, Typeable e) => c (t d a) -> Maybe (c (t e a)) 
myDataCast1 x = r 
    where 
    r = case typeOf (getArg x) == typeOf (getArg (fromJust r)) of 
      True -> Just $ unsafeCoerce x 
      False -> Nothing 
    getArg :: c (t x a) -> x 
    getArg = undefined 

Cette fonction vous pouvez, par exemple écrire foo

foo :: Typeable d => c (d, a) -> Maybe (c (Int, a)) 
foo = myDataCast1 
+0

fermer, mais non :-). Le bit délicat est de faire correspondre la façon dont dataCast produit quelque chose de type 'Data a => Peut-être (c a)' - c'est-à-dire que son résultat n'a aucun constructeur de type à l'exception du 'c'.Pour voir pourquoi cela est nécessaire, essayez de jouer avec 'Data.Generics.Aliases' et considérez pourquoi' ext1Q' ne peut pas être écrit (du moins par moi) avec simplement 'gcast1' au lieu de' dataCast1'. – sclv

0

Selon cette paper la façon de mettre en œuvre dataCast1 est soit comme

dataCast1 f = gcast1 f -- for unuary type constructors 

ou

dataCast1 f = Nothing -- for non-unary type constructors 

Ils n'ont pas dit que c'est la seule façon de l'implémenter, mais c'est peut-être le cas. Peut-être que cela vaut la peine de demander aux auteurs? Je pense que le problème principal est que nous ne pouvons pas appliquer partiellement les constructeurs de types. par exemple. ce qui suit n'est pas possible

data T a b = ... 

instance Typeable a => Data (T Int) where 
    dataCast1 f = ... 

GHC se plaindra que T n'a pas été appliqué à suffisamment d'arguments de type.

Je peux penser à une solution de rechange. Nous définissons un nouveau type

newtype PairInt a = PairInt (Int, a) deriving Typeable 

instance (Typeable a, Data a) => Data (PairInt a) where 
    dataCast1 f = gcast1 f 

C'est assez ennuyeux mais ça fait l'affaire. Mais peut-être que cela ne correspond pas à ce que vous essayez d'accomplir.