Frage

Wie kann ich den Einsatz von Generalized Algebraische Datentyp machen?

Das Beispiel in der Haskell Wikibook ist zu kurz, um mir einen Einblick die tatsächlichen Möglichkeiten der GADT.

War es hilfreich?

Lösung

habe ich die „Eingabeaufforderung“ Monade gefunden (aus dem „MonadPrompt“ -Paket) ein sehr nützlichen Werkzeug an mehreren Stellen (zusammen mit der äquivalent „Programm“ Monade von dem „operational“ Paket. In Kombination mit GADTs (das ist, wie es bestimmt wurde verwendet werden), ermöglicht es Ihnen sehr billig eingebettete Sprachen zu machen und sehr flexibel. es war ein href ein ziemlich guter Artikel des <= "http://themonadreader.files.wordpress.com/2010/01/issue15 .pdf“rel =‚noreferrer‘> Monad Reader Ausgabe 15 namens‚Abenteuer in drei Monaden‘, die zusammen mit einigen realistischen GADTs eine gute Einführung in die Eingabeaufforderung Monade hatte.

Andere Tipps

GADTs sind schwache Annäherungen von induktiven Familien aus abhängig typisierten Sprachen-so lassen Sie uns beginnen dort statt.

Induktiv Familien sind die Kern-Datentyp Einführung Methode in einer abhängig typisierte Sprache. Zum Beispiel in Agda definieren Sie die natürlichen Zahlen wie diese

data Nat : Set where
  zero : Nat
  succ : Nat -> Nat 

, die nicht sehr extravagant ist, ist es im Wesentlichen nur das gleiche wie die Haskell Definition

data Nat = Zero | Succ Nat

und in der Tat in GADT Syntax der Haskell Form ist noch ähnlicher

{-# LANGUAGE GADTs #-}

data Nat where
  Zero :: Nat
  Succ :: Nat -> Nat

Also, auf den ersten Blick könnte man denken, GADTs sind nur ordentlich zusätzliche Syntax. Das ist nur die Spitze des Eisbergs.


hat Agda Fähigkeit, alle Arten von Typen ungewohnt und fremd einen Haskell Programmierer darzustellen. Ein einfacher ist die Art der endlichen Mengen. Diese type ist wie Fin 3 geschrieben und stellt die Satz von Zahlen {0, 1, 2}. Ebenso Fin 5 stellt den Satz von Zahlen {0,1,2,3,4}.

Dies sollte an dieser Stelle recht bizarr sein. Erstens, wir bezogen auf eine Art, die eine reguläre Nummer als „Typ“ Parameter hat. Zweitens ist klar, es nicht das, was es für Fin n bedeutet den Satz {0,1...n} darzustellen. Im wirklichen Agda würden wir etwas stärker, aber es genügt zu sagen, dass wir eine contains Funktion definieren

contains : Nat -> Fin n -> Bool
contains i f = ?

Dies ist nun wieder seltsam, weil die „natürliche“ Definition von contains so etwas wie i < n sein würde, aber n ist ein Wert, der in der Art Fin n existiert nur, und wir sollten diese Kluft überqueren so leicht nicht in der Lage sein. Während es stellt sich heraus, dass die Definition nicht annähernd so einfach ist, das ist genau die Kraft, die induktive Familien in Abhängigkeit eingegeben haben Sprachen-sie-Werte vor, die auf ihre Typen und Arten ab, die auf ihren Werten abhängen.


Wir können untersuchen, was es über Fin ist, dass es diese Eigenschaft gibt, indem du ihre Definition suchen.

data Fin : Nat -> Set where
  zerof : (n : Nat) -> Fin (succ n)
  succf : (n : Nat) -> (i : Fin n) -> Fin (succ n)

Dies dauert ein wenig Arbeit zu verstehen, um ein Beispiel versuchen können, einen Wert des Typs Fin 2 zu konstruieren. Es gibt ein paar Möglichkeiten, dies zu tun (in der Tat finden wir, dass es genau 2)

zerof 1           : Fin 2
zerof 2           : Fin 3 -- nope!
zerof 0           : Fin 1 -- nope!
succf 1 (zerof 0) : Fin 2

So können wir sehen, dass es zwei Einwohner und zeigt auch ein wenig wie Typ Berechnung geschieht. Insbesondere spiegelt die (n : Nat) Bit in der Art der zerof die tatsächliche Wert n in der Art nach oben ermöglicht es uns, Fin (n+1) für jede n : Nat zu bilden. Danach haben wir wiederholte Anwendungen von succf verwenden unsere Fin Werte nach oben in den richtigen Typ Familie Index (natürliche Zahl, die Indizes der Fin) zu erhöhen.

Was bietet diese Fähigkeiten? In aller Ehrlichkeit gibt es viele Unterschiede zwischen einer abhängig getippt induktiven Familie und einem regelmäßigen Haskell ADT, aber wir können auf dem genauen einem konzentrieren, die relevant für das Verständnis GADTs ist.

In GADTs und induktive Familien erhalten Sie die Möglichkeit, die angeben genau Typ Ihres Konstrukteurs. Dies könnte langweilig sein

data Nat where
  Zero :: Nat
  Succ :: Nat -> Nat

Oder, wenn wir einen flexibleren, indizierte Art haben, können wir verschiedenen wählen, interessante Rückgabetypen

data Typed t where
  TyInt  :: Int                -> Typed Int
  TyChar :: Char               -> Typed Char
  TyUnit ::                       Typed ()
  TyProd :: Typed a -> Typed b -> Typed (a, b)
  ...

Insbesondere wir missbrauchen die Fähigkeit, den Rückgabetyp zu ändern basierend auf der insbesondere Wert Konstruktor verwendet. Dies ermöglicht es uns, einige Wertinformationen zu reflektieren bis in die Art und produzieren mehr fein spezifiziert (fibered) eingegeben haben.


Also, was können wir mit ihnen machen? Nun, mit ein wenig Fett Ellenbogen wir können produzieren Fin in Haskell . Kurz und bündig erfordert es, dass wir eine Vorstellung von Naturals in Typen

definieren Genracodicetagpre

... dann ein GADT Werte in diesen Typen zu reflektieren bis ...

data Z
data S a = S a

> undefined :: S (S (S Z))  -- 3

... dann können wir diese zu bauen Fin verwenden viel wie wir in Agda tat ...

data Nat where
  Zero :: Nat Z
  Succ :: Nat n -> Nat (S n)

Und schließlich können wir bauen genau zwei Werte von Fin (S (S Z))

data Fin n where
  ZeroF :: Nat n -> Fin (S n)
  SuccF :: Nat n -> Fin n -> Fin (S n)

Beachten Sie aber, dass wir eine Menge Komfort über den induktiven Familien verloren haben. Zum Beispiel können wir nicht regelmäßig Zahlenliterale in unseren Typen verwenden (obwohl das technisch nur ein Trick in Agda sowieso ist), brauchen wir eine separate „Typ nat“ und „Wert nat“ zu schaffen und die GADT nutzen sie miteinander zu verbinden, und wir würden auch in der Zeit finden, dass, während Typ-Ebene Mathematik ist schmerzhaft in Agda es kann getan werden. In Haskell es ist unglaublich schmerzhaft und oft kann es nicht.

Zum Beispiel ist es möglich, eine weaken Vorstellung in Agda der Fin Typen definieren

*Fin> :t ZeroF (Succ Zero)
ZeroF (Succ Zero) :: Fin (S (S Z))

*Fin> :t SuccF (Succ Zero) (ZeroF Zero)
SuccF (Succ Zero) (ZeroF Zero) :: Fin (S (S Z))

, wo wir einen sehr interessanten ersten Wert liefern, ein Beweis dafür, dass n <= m die uns einzubetten „ein Wert von weniger als n“ in den Satz von „Werten von weniger als m“. Das können wir auch in Haskell tun, technisch, aber es erfordert schweren Missbrauch von Typklasse Prolog.


So ist GADTs eine Ähnlichkeit von induktiven Familien in Abhängigkeit typisierten Sprachen, die schwächer und schwerfälliger sind. Warum tun wir sie in Haskell in erster Linie wollen?

Im Grunde genommen, weil nicht alle Typen Invarianten erfordert die volle Leistung der induktiven Familie zum Ausdruck bringen und GADTs holt einen bestimmten Kompromiss zwischen Ausdruckskraft, Umsetzbarkeit in Haskell und Typinferenz.

Einige Beispiele von nützlichen GADTs Ausdrücke sind Rot-Schwarz-Bäume, die nicht haben das rot-Schwarz-Eigenschaft für ungültig erklärt oder einfach-typisierten Lambda-Kalkül eingebettet als HOAS huckepack vom Typ System Haskell.

In der Praxis auch oft sehen GADTs für ihren impliziten Existenz Kontext verwenden. Zum Beispiel kann der Typ

weaken : (n <= m) -> Fin n -> Fin m
weaken = ...

verbirgt sich implizit die a Typ Variable existentielle Quantifizierung

data Foo where
  Bar :: a -> Foo

in einer Weise, die manchmal bequem ist. Wenn Sie genau das HOAS Beispiel aus Wikipedia suchen verwendet diese für die a Typ-Parameter im App Konstruktor. Um auszudrücken, diese Aussage ohne GADTs würde ein Durcheinander von existenziellen Kontexten, aber die GADT Syntax macht es natürlich.

GADTs dich stärker Art erzwungen Garantien geben als normale ADTs. Zum Beispiel können Sie einen binären Baum zwingen, von der Art der Systemebene ausgeglichen werden, wie in diese Implementierung von 2-3 Bäume :

{-# LANGUAGE GADTs #-}

data Zero
data Succ s = Succ s

data Node s a where
    Leaf2 :: a -> Node Zero a
    Leaf3 :: a -> a -> Node Zero a
    Node2 :: Node s a -> a -> Node s a -> Node (Succ s) a
    Node3 :: Node s a -> a -> Node s a -> a -> Node s a -> Node (Succ s) a

Jeder Knoten hat eine Typ-kodierte Tiefe, in der alle seine Blätter befinden. Ein Baum ist dann entweder ein leerer Baum, ein Singleton-Wert oder ein Knoten unspezifizierter Tiefe, wieder mit GADTs.

data BTree a where
    Root0 :: BTree a
    Root1 :: a -> BTree a
    RootN :: Node s a -> BTree a

Das Typsystem garantiert Ihnen, dass nur ausgeglichen Knoten aufgebaut werden kann. Dies bedeutet, dass, wenn Operationen wie insert auf solche Bäume Umsetzung Ihrer Codetyp-Kontrollen nur dann, wenn das Ergebnis ist immer ein ausgeglichener Baum.

I wie das Beispiel in das GHC Handbuch . Es ist eine schnelle Demo eines GADT Idee Kern: dass Sie den Typ System einer Sprache einbetten können Sie sind Manipulieren in Haskell Typ-System. Auf diese Weise können Sie Ihre Haskell Funktionen übernehmen, und zwingt sie zu erhalten, dass die Syntaxbäume zu gut getippt Programme entsprechen.

Wenn wir Term definieren, spielt es keine Rolle, welche Arten wir wählen. Wir konnten schreiben

data Term a where
  ...
  IsZero :: Term Char -> Term Char

oder

  ...
  IsZero :: Term a -> Term b

und die Definition von Term noch würde gehen.

Es ist nur, wenn wir auf berechnen möchten Term, wie in eval definiert, dass die Typen Materie. Wir müssen haben

  ...
  IsZero :: Term Int -> Term Bool

, weil wir unseren rekursiven Aufruf zu eval brauchen eine Int zurückzukehren, und wir möchten, um wiederum eine Bool zurück.

Dies ist eine kurze Antwort, aber die Haskell Wikibook konsultieren. Er führt Dich zwar ein GADT für einen gut typisierten Ausdruck Baum, der ein ziemlich kanonisches Beispiel ist: http: //en.wikibooks.org/wiki/Haskell/GADT

GADTs sind auch für die Umsetzung der Art Gleichheit verwendet: http://hackage.haskell.org/package / Art-Gleichheit . Ich kann nicht das richtige Papier zu Referenz für dieses ohne Weiteres finden - diese Technik gemacht mittlerweile seinen Weg auch in der Folklore hat. Es ist ganz gut, aber verwendet, in Olegs getippt tagless Sachen. Siehe z.B. der Abschnitt über getippt Kompilation in GADTs. http://okmij.org/ftp/tagless-final/#tc-GADT

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top