2013-03-20 11 views
7

Supponiamo che io ho il seguente codice:Come posso ottenere GHC per generare istanze di Data.Typeable per GADTs con Typeable nel contesto?

{-# LANGUAGE GADTs, DeriveDataTypeable, StandaloneDeriving #-} 
import Data.Typeable 

class Eq t => OnlyEq t 
class (Eq t, Typeable t) => BothEqAndTypeable t 

data Wrapper a where 
    Wrap :: BothEqAndTypeable a => a -> Wrapper a 

deriving instance Eq (Wrapper a) 
deriving instance Typeable1 Wrapper 

Poi, la seguente dichiarazione di istanza funziona, senza un vincolo sulla t:

instance OnlyEq (Wrapper t) 

e fa quello che mi aspetto di fare.


Ma la seguente dichiarazione di istanza non funziona:

instance BothEqAndTypeable (Wrapper t) 

dal GHC - sto usando 7.6.1 - lamenta che:

No instance for (Typeable t) 
    arising from the superclasses of an instance declaration 
Possible fix: 
    add (Typeable t) to the context of the instance declaration 
In the instance declaration for `BothEqAndTypeable (Wrapper t)' 

Aggiunta Typeable t al contesto funziona, ovviamente. Ma così aggiunge l'istanza seguente:

instance Typeable (Wrapper t) where 
    typeOf (Wrap x) = typeOf1 (Wrap x) `mkAppTy` typeOf x 

C'è un modo per ottenere GHC per scrivere quest'ultima istanza per me? Se é cosi, come? Se no, perché no?

Speravo che GHC fosse in grado di estrarre il vincolo Typeable dal contesto nel costruttore Wrap, proprio come ha fatto con il vincolo Eq. Penso che i miei problemi si riducano al fatto che GHC non consente esplicitamente di scrivere deriving instance Typeable (Wrapper t) e l'istanza standard (Typeable1 s, Typeable a) => Typeable (s a) non può "cercare all'interno" s a per trovare un dizionario Typeable a.

risposta

5

Speravo GHC sarebbe in grado di tirare il vincolo Typeable dal contesto in Wrap costruttore

Se avesse avuto un costruttore Wrap, potrebbe tirare il vincolo Typeable da esso.

Ma non ha un costruttore Wrap.

La differenza è che l'istanza Eq utilizza il valore, quindi è sia un Wrap something, in cui il costruttore Wrap rende il Eq dizionario per il tipo avvolto disponibile, e tutto è bene, o è , e quindi tutto è bene troppo , valutando i fondi x == y.

noti che la derivata

instance Eq (Wrapper a) 

fa non ha un Eq vincolo sul tipo di variabile a.

Prelude DerivT> (undefined :: Wrapper (Int -> Int)) == undefined 
*** Exception: Prelude.undefined 
Prelude DerivT> (undefined :: (Int -> Int)) == undefined 

<interactive>:3:29: 
    No instance for (Eq (Int -> Int)) arising from a use of `==' 
    Possible fix: add an instance declaration for (Eq (Int -> Int)) 
    In the expression: (undefined :: Int -> Int) == undefined 
    In an equation for `it': 
     it = (undefined :: Int -> Int) == undefined 

Ma l'istanza Typeable non deve fare uso del valore, quindi non c'è alcun toccare il fondo, se il valore fornito non è un Wrap something.

quindi il derivato instance Typeable1 Wrapper fornisce

instance Typeable t => Typeable (Wrapper t) 

ma non un vincolata

instance Typeable (Wrapper t) 

e tale istanza vincoli non possono essere derivati ​​da GHC.

Quindi bisogna o fornire una vincolato

instance Typeable t => BothEqAndTypeable (Wrapper t) 

o un non vincolata

instance Typeable (Wrapper t) 

te stesso.

+1

Destra, continuo a dimenticare i punti più fini di "indefinito" poiché di solito immagazzino qualcosa nei miei tipi di dati :-) Penso di aver bisogno di una sorta di GADT 'newtype', quindi! E un'ulteriore domanda, se posso: è l'istanza non costruibile 'Typeable (Wrapper t)' che ho scritto in qualche modo male, a patto che non mi interessi che 'typeOf (errore" aargh ":: Wrapper Bool)' ritorna in basso? – yatima2975

+2

Beh, è ​​un'istanza un po 'sorprendente dal momento che non puoi usarla con 'undefined :: Wrapper Bool' come le altre istanze' Typeable'. Se lo fai pubblico, metti almeno un avvertimento su di esso. Ma non penso che dovrebbe necessariamente fermarti. Nelle future versioni di GHC, tuttavia, a partire dal 7.8, tutte le istanze 'Typeable' saranno fornite da GHC e, per tutti i tipi, iirc. Quindi non dovrai più affrontare questi problemi. –

+1

Guardando il repository, avrai bisogno di '-XAutoDeriveTypeable'. Freddo! Penso che * potrei * andare a clonare 7.8.1 nel fine settimana per quello, ma l'ultima volta che ho costruito GHC è stato nel 2002 (inizio del ciclo 6.x?), Quindi è un po 'spaventoso ... Ma grazie ancora! – yatima2975

Problemi correlati