2012-06-22 12 views
18

GHC hat einige Sprachflags, wie DeriveFunctor, DeriveDataTypeable usw., die die Compilergenerierung abgeleiteter Instanzen für andere Typklassen als die in Haskell 98 erlaubten ermöglichen. Dies macht insbesondere für Functor Sinn, wo die Gesetze dieser Klasse diktieren eine offensichtliche, "natürliche" abgeleitete Instanz.Warum kann GHC keine Instanzen für Monoid ableiten?

Also warum nicht für Monoid? Es scheint, wie für jeden Datentyp mit einem einzigen Datum Konstruktor:

data T = MkT a b c ... 

man könnte eine Monoid Instanz mechanisch erzeugt (entschuldigen Sie den Pseudo-Code):

instance (Monoid a, Monoid b, Monoid c, ...) => Monoid T where 
    mempty = 
    MkT mempty mempty mempty ... 
    mappend (MkT a1 b1 c1 ...) (MkT a2 b2 c2 ...) = 
    MkT (mappend a1 a2) (mappend b1 b2) (mappend c1 c2) ... 

Ich bin mir bewusst, dass das Paket deriveprovides this, aber meine Frage ist speziell, ob es einen Grund gibt, warum GHC das nicht tut.

+0

@sdcvvc: Dies scheint wie eine gültige Antwort auf die Frage. Vielleicht sollten Sie es als solches posten? –

+0

OK, ich habe eine Antwort gegeben. – sdcvvc

+1

Es gibt normalerweise nur eine vernünftige Möglichkeit, eine 'Functor'-Instanz zu erstellen. Das Gleiche gilt nicht für "Monoid". – augustss

Antwort

14

Es ist wirklich eine willkürliche Entscheidung, Monoid nicht abzuleiten, aber Monoids sind auch sehr allgemein, so gibt es normalerweise viele Weisen, einen Typ ein Monoid zu machen. Hier ein Beispiel:

data T = A | B | C deriving (Eq, Ord, Enum) 

type Mon a = (a, a -> a -> a) 

m1, m2, m3, m4 :: Mon T 
m1 = (A, max) 
m2 = (C, min) 
m3 = (A, \ x y -> toEnum $ (fromEnum x + fromEnum y) `rem` 3) 
m4 = (B, f4) 
f4 A _ = A 
f4 B x = x 
f4 C _ = C 

Dies zeigt vier vernünftige Wege T ein Monoid zu machen (mit Mon das Gerät enthält, und die binäre Operation). Das erste ist das Monoid, das das Maximum nimmt, das zweite das Monoid, das das Minimum annimmt, das dritte das Monoid von der Modulo 3-Arithmetik, und das vierte ist das für den Typ Ordering verwendete Monoid. Nichts steht wirklich als natürlicher Weg heraus.

7

Sie könnten dasselbe für Num und einige andere Klassen fragen. Es wäre belanglos: Alle anderen Standardableitungen funktionieren für Datentypen mit mehreren Konstruktoren.

Als Ersatz können Sie newtype derivating newtype T = MkT (a,b,c) deriving Monoid verwenden.

Ähnliche Erweiterung: Sie können den leeren Datentyp eine Instanz fast jeder Typklasse machen.

Die deriving Klausel war immer ad-hoc und unbequem Teil der Haskell, weil es nur für vordefinierte Klassen funktionierte. Das Hinzufügen von noch mehr Ad-hoc-Erweiterungen würde die Sprache komplizieren. Stattdessen hat GHC kürzlich Unterstützung für generic deriving erhalten.

+1

Nun, wie Ad-hoc- "Ableiten" kann, haben sie ihre Macht weiter ausgebaut. Wiederum weiß ich, dass es alternative Mechanismen gibt, um 'Monoid' abzuleiten; stattdessen frage ich speziell, warum "DeriveFunctor" (und andere) existiert, während "DeriveMonoid" (und andere) nicht existiert. Ist es nur willkürlich? – mergeconflict

+2

Am Ende ist es willkürlich, aber die vorgeschlagene Erweiterung scheint viel weniger nützlich zu sein. Eine spezielle Sprachfunktion für die meisten Funktoren scheint mir gut zu sein. Eine spezielle Sprachfunktion, um Produktmonoiden zu servieren, scheint zu wenig hinzuzufügen. Du müsstest über Umfang nachdenken (wenn 'Monoid' dann welche anderen Klassen?). Beachten Sie, dass nützliche Monoids oft Newtyp-Wrapper verwenden. Also schreibst du 'data T = T (Sum Integer) (Endo Char)', um diese Form der Ableitung zu verwenden, die etwas hässlich zu benutzen ist (sie muss bei verschachtelten Konstruktoren übereinstimmen). – sdcvvc

+2

Es gibt viele nützliche Monoids, die Sum-Typen sind, aber diese Implementierung kann keine ihrer Instanzen ableiten.= ( –

Verwandte Themen