Ich las William Cooks "On Data Abstraction, Revisited" und las erneut Ralf Laemmels "The Expression Lemma", um zu versuchen zu verstehen, wie man die Ideen des früheren Papiers in Haskell anwendet. Also, ich versuche zu verstehen, wie Sie in Haskell beispielsweise eine Set-Union-Funktion implementieren könnten, ohne die Typen anzugeben?Wie deklariert man einen abstrakten Datencontainertyp in Haskell?
Antwort
es mehr Möglichkeiten gibt, je nachdem, welche Version von „abstrakten Datentypen“ sind Sie nach.
Betons aber undurchsichtiger Typ: Es ist schon eine Weile, da ich Cook schönes Papier lesen, aber wieder darüber denke ich Streif dies am nächsten ist, was er über als ADTs sprechen. Die Standardmethode in Haskell besteht darin, einen Typ ohne seine Konstruktoren zu exportieren. was das bedeutet in Haskell:
Kein Muster
Keine Konstruktion Werte des Typs auf Werte der abstrahierten Typ passend, mit Ausnahme von seinem Modul exportierten Funktionen mit
Wie diese bezieht sich auf Cooks Papier:
Repräsentationsunabhängigkeit: Von außen ist die Darstellung nicht zugänglich.
Überprüfung mehrerer Darstellungen: Innerhalb des ADT-Moduls können Darstellungen frei geprüft werden.
Einzigartige Implementierungen/Module: Unterschiedliche Implementierungen können durch verschiedene Module zur Verfügung gestellt werden, aber die Typen außer mit normalen Mitteln nicht zusammenarbeiten können. Sie können
Data.IntMap.null
nicht verwenden, um zu sehen, ob eineData.Map.Map Int a
leer ist.
Diese Technik wird ausführlich in den Haskell Standardbibliotheken verwendet werden, insbesondere für die Datentypen, die irgendeine Art von Invarianten oder auf andere Weise beschränken die Fähigkeit, Werte zu konstruieren pflegen müssen. Also in diesem Fall, ist der beste Weg, um die Set ADT aus dem Papier zu implementieren, ist der folgende Code:
import qualified Data.Set as S
Obwohl dies vielleicht nicht so mächtig ein Mittel der Abstraktion, wie sie in einer Sprache mit einem ausdrucksvollen sein könnten Modulsystem.
Existentielle Quantifizierung und Schnittstelle: Haskell nicht wirklich ein
exists
Stichwort als solche, aber der Begriff „Existenz“ wird unter verschiedenen Umständen verwendet, um bestimmte Arten von polymorphen Typen zu beschreiben. Die allgemeine Idee ist in jedem Fall, einen Wert mit einer Sammlung von Funktionen zu kombinieren, so dass das Ergebnis im Werttyp polymorph ist.Betrachten Sie diese Funktion Unterschrift:foo :: (a, a -> Bool) -> Bool
Obwohl es einen Wert vom Typ empfängt
a
, weila
vollständig polymorph ist das einzige, was es möglicherweise mit diesem Wert tun kann, ist die Funktion für sie gelten. In diesem Sinne ist die erste Hälfte des Tupels gewissermaßen ein "abstrakter Datentyp", während die zweite Hälfte eine "Schnittstelle" für die Arbeit mit diesem Typ ist. Wir können diese Idee explizit machen, und es außerhalb einer einzigen Funktion anwenden, einen existentieller Datentyp:data FooADT = forall a. FooADT a (a -> Bool) foo :: FooADT -> Bool
Nun wird jedes Mal, wenn wir einen Wert vom Typ haben
FooADT
, alles, was wir wissen ist, dass existiert irgendein Typa
so, dass wirFooADT
s zweites Argument zu seinem ersten anwenden können.Dieselbe Idee gilt für polymorphe Typen mit Klassenbeschränkungen; Der einzige Unterschied besteht darin, dass die Funktionen, die auf dem Typ ausgeführt werden, implizit von der Typklasse bereitgestellt werden und nicht explizit mit dem Wert gebündelt werden.
Nun, was bedeutet dies in Bezug auf Cooks Papier?
Darstellung Unabhängigkeit gilt nach wie vor.
Gesamtisolation: Im Gegensatz zu früher ist die Kenntnis des existentiell quantifizierten Typs für immer verloren. Nichts kann die Repräsentation überprüfen, außer der Schnittstelle, die sie selbst bereitstellt.
Beliebige Implementierungen: Nicht nur sind Implementierungen nicht unbedingt einzigartig, es gibt keine Möglichkeit, sie überhaupt zu begrenzen! Alles, was die gleiche Schnittstelle zur Verfügung stellen kann, kann in ein existenzielles eingebettet werden und von anderen Werten nicht zu unterscheiden sein.
Kurz gesagt, das ist Cooks Beschreibung von Objekten sehr ähnlich. Für weitere existenzielle ADTs ist das Papier Unfolding Abstract Datatypes kein schlechter Startpunkt; aber bedenken Sie, dass das, was es diskutiert, grundsätzlich nicht das ist, was Cook eine ADT nennt.
Und ein kurzer Nachtrag: Nach oben zu all der Mühe gemacht existenzielle Art Abstraktionen zu beschreiben, würde Ich mag etwas über den FooADT
Typen markieren: Weil alles, was Sie tun können, damit das ist anzuwenden Funktion, um ein Bool
Ergebnis zu erhalten, gibt es grundsätzlich keinen Unterschied zwischen FooADT
und Bool
, außer dass der ehemalige verschleiert Ihren Code und erfordert GHC-Erweiterungen. Ich ermutige dringend reading this blog post, bevor Sie existentielle Typen im Haskell-Code verwenden.
Danke, camccann, das war eine hervorragende Antwort - gründlich, aufschlussreich und zum Nachdenken anregend. (Nebenbei habe ich diesen Eintrag auf luquis Blog mindestens drei Mal gelesen ... versuche immer noch, ihn dazu zu bringen, dass er versinkt.) – BMeph
Sie können entweder eine Vergleichsfunktion anfordern oder die Typen als Instanzen von Gl. Siehe nub
und nubBy
für Beispiele für diese Technik:
nub :: (Eq a) => [a] -> [a]
nubBy :: (a -> a -> Bool) -> [a] -> [a]
- 1. Wie deklariert man einen Allokator?
- 2. Wie deklariert man einen Kartentyp in Typoskript?
- 3. Wie man einen Methodenparameter als enum deklariert
- 4. Wie man einen Baum in Haskell schmückt
- 5. Wie man Besuchermuster für einen abstrakten Syntaxbaum in C# schreibt?
- 6. Wie deklariert man in TypeScript einen Typ als Nullable?
- 7. Wie deklariert man einen void Zeiger in C#
- 8. Wie deklariert man einen String in Objective-C?
- 9. Wie deklariert man einen Namensraum in WPF XAML?
- 10. Wie deklariert man einen Empfänger in einem Service im Manifest?
- 11. Wie kann man einen Parameter eines abstrakten Datentyps haben?
- 12. Wie deklariert man Eingaben in Rcpp-Funktionen?
- 13. Wie man Variablen in jQuery richtig deklariert
- 14. Wie deklariert man 2D-Arrays in Haxe?
- 15. Wie deklariert man z in Akkordeon
- 16. Wie deklariert man einen generischen Delegaten mit einem out-Parameter
- 17. Wie löst man in Haskell einen Typ-Familienmuster-Übereinstimmungsfehler aus?
- 18. Wie erhält man einen ASCII-Wert von Charakter in Haskell?
- 19. Wie bekomme ich einen Zeigerwert in Haskell?
- 20. Wie man den Reader Monad benutzt, wenn man einen abstrakten Syntaxbaum durchläuft
- 21. Lernen Haskell: Wie man einen Gegenstand von einer Liste in Haskell entfernt
- 22. Wie deklariert man eine Int64-Konstante?
- 23. Wie man Funktion und Monadenaktion in Haskell
- 24. Wie man ein Swift Array deklariert
- 25. Haskell: Wie man einen Typ von zwei Typklassen erzeugt?
- 26. bash - Wie deklariert man eine lokale Ganzzahl?
- 27. deklariert einen classmember in einer anderen
- 28. Wie man array of handel deklariert?
- 29. Wie deklariert man zwei nicht zuordenbare Typen?
- 30. Wie man eine Struktur in Haskell "entpackt"
Über Typklassen, die Ihnen erlauben, die Funktion zu modellieren und in beiden Datentypen und Funktionen zu ersetzen? –