2016-03-28 10 views
3

Sorry über schlechten Titel. Ich habe einen problematischen Datentyp, den ich als Instanz von funktor definieren möchte.Haskell: Funktor von diesem Datentyp?

Also im Grunde, was ich habe, ist etwas, das

sample_logp :: s a -> a 

hat und es sollte

(a -> b) 

zu

sample_logp :: s b -> b 

mit umgewandelt werden. Der folgende Code erreicht dies nicht ganz und nur in

sample_logp :: s a -> b 

.

data Model s a = Model { 
    sample_logp :: s a -> a 
} 

instance Functor (Model s) where 
    fmap f m = Model { 
    sample_logp = sample_logp' 
    } where sample_logp' x = (f . (sample_logp m)) x 

Ist was ich versuche sogar möglich? Wenn ja, wie könnte dieser Code aktualisiert werden, um dies zu erreichen?

+8

Es kann kein Funktor sein: 'a' ist sowohl kovariant als auch kontravariant. – zakyggaps

+0

Danke! Gibt es in diesem Fall eine andere Klassenklasse, die das erreichen würde? – tero

+3

Sie können [Profunctor] (http://hackage.haskell.org/package/profctors-5.2/docs/Data-Profunctor.html) überprüfen, aber die Designauswahl hängt stark davon ab, was "s" ist. – zakyggaps

Antwort

9

Der Standardansatz besteht darin, weitere Typvariablen hinzuzufügen.

data Model s a b = Model { 
    sample_logp :: s a -> b 
} 

Sobald Sie die Typvariablen aufgeteilt haben, haben Sie Zugriff auf weitere Tools. Die Klasse Profunctor ist hier angebracht. (Nicht typechecked da ich nicht ghc auf diesem System haben -. Kommentar oder einfach nur beheben, wenn meine Implementierung ausgeschaltet ist)

instance (Functor s) => Profunctor (Model s) where 
    dimap f g (Model h) = Model $ g . h . fmap f 
    lmap f (Model h) = Model $ h . fmap f 
    rmap g (Model h) = Model $ g . h 

nun gegeben, dass Sie eine Model s a a haben, das entspricht Ihrer Model s a ist, Sie können es in Model s b b umwandeln, indem Sie dimap bToA aToB verwenden.

Wie die Kommentare sagen, ist Ihr ursprünglicher Datentyp invariant, da er die gleiche Typvariable in positiver und negativer Position verwendet. Dies bedeutet, dass Sie Konvertierungsfunktionen in jeder Richtung bereitstellen müssen. Wenn Sie eine zusätzliche Typvariable hinzufügen, können Sie die vorhandenen Tools dafür nutzen, wie zum Beispiel Profunctor.


Beachten Sie, dass alle oben auf der Annahme basiert, dass Sie covariant Typen für s verwenden. Wenn s kontravariant ist, dann können Sie eine direkte Functor Instanz für Ihren ursprünglichen Typ schreiben, wie der Kommentar von chi sagt. Das ist jedoch eine viel weniger häufige Situation.

Verwandte Themen