2014-10-24 19 views
7

ho un "lineare" di tipo familiare, cioè della formaInversione di una famiglia tipo

type family Foo a 
type instance Foo T1 = T2 
type instance Foo T2 = T3 
... 
type instance Foo T9 = T10 

Nel mio particualr caso d'uso, è molto comodo per definire il "reverse" famiglia FooRev e poi rispettare il vincolo (FooRev (Foo x) ~ x):

type family FooRev a 
type instance FooRev T10 = T9 
type instance FooRev T9 = T8 
... 
type instance FooRev T2 = T1 

la famiglia inversa consente GHC inferire molti tipi che altrimenti sarebbero ambiguo a causa del mancato iniettivita. È essenzialmente la stessa idea che è stata proposta here. Questa soluzione funziona piuttosto bene, ma è fastidioso, programmatico e soggetto a errori definire una famiglia di tipo "inverso" elencando tutti i casi. Esiste un modo più generico per definire il contrario di una famiglia lineare come Foo?

+2

Forse potresti usare in qualche modo le famiglie di 'data', che sono note iniettivo. Non sono sicuro se si adatta al tuo problema. – luqui

+0

La metaprogrammazione (ad esempio il modello Haskell) potrebbe generare entrambi, mantenendo il codice ASCIUTTO se questo è il tuo problema. Altrimenti, è possibile definire un elenco di associazioni a livello di testo, una ricerca a livello di testo, un 'livello di scambio di tipo livello e derivare entrambe le famiglie di tipi dall'elenco. – chi

+0

@luqui L'ho appena visto prima di postare, ma per quanto ne so, non è proprio quello di cui ho bisogno. Nel mio caso, i 'Ti' sono tutti di tipo' Bar a b c' dove cambiano i parametri del tipo. Non andrà bene in una famiglia di dati, vero? – crockeea

risposta

5

Ho deciso di dare l'idea di @ chi provare, ma alla fine mi è venuto in mente qualcosa di più semplice.

{-# LANGUAGE TypeOperators, DataKinds, TypeFamilies #-} 

type family NextElt (a :: *) (xs :: [*]) where 
    NextElt a (a ': b ': cs) = b 
    NextElt a (b ': c ': cs) = NextElt a (c ': cs) 

type family PrevElt (a :: *) (xs :: [*]) :: * where 
    PrevElt a (b ': a ': xs) = b 
    PrevElt a (b ': c ': xs) = PrevElt a (c ': xs) 

data T1 
data T2 
data T3 
type TSeq = '[T1, T2, T3] 

type NextRp a = NextElt a TSeq 
type PrevRp a = PrevElt a TSeq 

Utilizzando un elenco di tipo per rappresentare la sequenza lineare di tipi mi permette di esprimere la relazione senza scrivere ogni tipo due volte (che è necessario, con le istanze di tipo di famiglia o le istanze di una classe). Le famiglie di tipi precedenti utilizzano un approccio a finestra scorrevole per cercare un elemento in una lista con un elemento precedente o successivo. Queste famiglie di tipi sono generiche (e possono essere estese per i tipi non * utilizzando Data.Type.Equality.)

5

Penso FunctionalDependencies dovrebbe essere la soluzione migliore per il vostro caso:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} 

class Foo a b | a -> b, b -> a 
instance Foo T1 T2 
instance Foo T2 T3 
... 

Ora ogni b si può dedurre da un a e viceversa.

Problemi correlati