2014-10-24 5 views
7

ich eine „lineare“ Art Familie habe, dh von der FormInvertierung eine Art Familie

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

In meinem particualr Anwendungsfall, es ist sehr bequem, die „umgekehrte“ Familie FooRev und dann zu definieren, erzwingen die Einschränkung (FooRev (Foo x) ~ x):

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

die umgekehrte Familie GHC viele Arten ableiten können, die ansonsten aufgrund nicht injectivity mehrdeutig sein würde. Es ist im Wesentlichen die gleiche Idee, die vorgeschlagen wurde here. Diese Lösung funktioniert ziemlich gut, aber es ist ärgerlich, programmatisch und fehleranfällig, eine "umgekehrte" Familie zu definieren, indem man alle Fälle auflistet. Gibt es eine allgemeinere Möglichkeit, die Rückseite einer linearen Familie wie Foo zu definieren?

+2

Vielleicht könnten Sie 'Daten' Familien stattdessen irgendwie verwenden, die bekannt sind injective. Nicht sicher, ob es zu Ihrem Problem passt. – luqui

+0

Metaprogrammierung (d. H. Vorlage Haskell) könnte beide generieren, halten Sie Ihren Code DRY, wenn das Ihr Anliegen ist. Andernfalls könnten Sie eine Zuordnungsliste auf Typfläche, eine Suche auf Typfläche, eine Map-Swap auf Typpebene und beide Typfamilien aus der Liste ableiten. – chi

+0

@luqui Ich habe das gerade vor dem Posten gesehen, aber soweit ich weiß, ist das nicht wirklich das, was ich brauche. In meinem Fall sind die "Ti" alle Typ "Bar a b c", wo sich die Typparameter ändern. Das passt nicht in eine Datenfamilie, oder? – crockeea

Antwort

5

Ich entschied mich, @ chis Idee zu versuchen, und aber ich kam etwas etwas einfacher am Ende.

{-# 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 

eine Typenliste Mit Hilfe der linearen Abfolge von Typen darzustellen ermöglicht es mir, die Beziehung auszudrücken, ohne jede Art zweimal zu schreiben (die Art Familie Instanzen oder Instanzen einer Klasse mit notwendig ist). Die obigen Typenfamilien verwenden einen gleitenden Fensteransatz, um nach einem Element in einer Liste mit einem vorherigen oder nächsten Element zu suchen. Diese Typenfamilien sind generisch (und können erweitert werden, um für nicht-* Arten mit Data.Type.Equality zu arbeiten.)

5

Ich denke FunctionalDependencies die beste Lösung für Ihren Fall sein sollte:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} 

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

Jetzt kann jeder b von einem a und umgekehrt zu entnehmen.

Verwandte Themen