2017-05-15 5 views
3

Instanz Entschuldigen Sie meine schlechte Englisch. Der Titel erklärt vielleicht nicht, was ich meine.wie Eq ohne Ableiten

In Data.Tree wird Tree wie folgt definiert:

-- | Multi-way trees, also known as /rose trees/. 
data Tree a = Node { 
     rootLabel :: a,   --^label value 
     subForest :: Forest a --^zero or more child trees 
    } 
#ifdef __GLASGOW_HASKELL__ 
    deriving (Eq, Read, Show, Data) 
#else 
    deriving (Eq, Read, Show) 
#endif 

Es deriving zum Beispiel == und /= für Tree (Datum) verwendet.

Kann ich das gleiche tun, ohne abzuleiten? Ich versuche, Dinge wie diese:

data Test a = Test a 
instance Eq Test where 
    (Test a) == (Test b) = a == b 

Aber es gibt eine Ausnahme aus. Ich denke, der Grund ist über die Arten von a und b.

Und was kann ich tun, wenn ich eine benutzerdefinierte Aktion für meine Daten mit == definieren möchte.

Ich weiß, ich kann Functor mit fmap verwenden, um es zu tun. Aber ich möchte == wie a == b verwenden, wo a = Test 1 und b = Test "a". Ist es möglich?

Antwort

9

Sie können eine instance von Eq auf Tree oder Test definieren, aber es gibt einige Probleme mit Ihrer Definition.

instance Eq Test where 
    (Test a) == (Test b) = a == b 

Eine erste ist, dass in TestEq Test ist noch parametrisiert. In der Tat haben Sie data Test a = ... geschrieben, was bedeutet, dass es einen Typ Parameter gibt. So können Sie es mit angeben:

instance Eq (Test a) where 
    (Test y) == (Test x) = x == y

nun so angegeben, dass Eq über Test a definiert ist. Ich habe auch a und b zu x und y umbenannt. Dies ist nicht notwendig, da die "type world" und "variable world" getrennt sind, aber es macht die Dinge weniger verwirrend.

Aber es gibt immer noch ein Problem: Sie rufen x == y. Aber gibt es keine Garantie, dass a selbst eine Instanz von Eq ist. Sie müssen daher mit einer Typeinschränkung arbeiten:

instance Eq a => Eq (Test a) where 
    (Test y) == (Test x) = x == y

Sie jetzt fest, dass Test a ist eine Instanz Eqwenna ist eine Instanz Eq auch.

Für Ihre Tree Datenstruktur, die instance von Eq sollte also wie folgt aussehen:

instance (Eq a, Eq (Forest a)) => Eq (Tree a) where 
    (Tree x1 y1) == (Tree x2 y2) = x1 == x2 && y1 == y2 

(natürlich hier definiere ich wie zwei Bäume gleich sind, ist es möglich, dass Sie die Gleichheit definieren wollen über zwei Bäume in einer (semantisch) anderen Weise, so sollten Sie nicht an sich kopieren diesen Code kopieren).

Beachten Sie, dass - wie @luqui sagt - wenn type Forest a = [Tree a], dann können Sie die Eq (Forest a) Typeinschränkung weglassen, da instance Eq a => Eq [a] hält. In diesem Fall ist es also:

instance Eq a => Eq (Tree a) where 
    (Tree x1 y1) == (Tree x2 y2) = x1 == x2 && y1 == y2 
+1

N.B. 'Forest a' ist ein Typensynonym für' [a] ', also ist technisch die' Eq (Forest a) 'Bedingung nicht notwendig, da' Eq a' bereits 'Eq [a]' impliziert. Aber diese Antwort ist angesichts der Parameter der Frage klar. – luqui

+0

@ Luqui: Sie haben Recht. Ich wusste nicht, dass ein Wald als '[Tree a]' definiert wurde (gut, es war möglich, dass einige zusätzliche Felder hinzugefügt wurden). Ich habe deine Antwort zusammen mit einem Kommentar zur Antwort hinzugefügt. Vielen Dank! –

+1

Die letzten beiden Instanzen fehlen 'Eq' in' Eq (Tree a) '. – chi