Listenverständnis
A Listenverständnis ist ein syntaktisch Konstrukt in einigen verfügbar Programmiersprachen zum Erstellen einer Liste basierend auf vorhanden Listen. Es folgt der Form der Mathematik Set-Builder-Notation (Verständnis festlegen) im Unterschied von der Verwendung von Karte und Filter Funktionen.
Überblick
Betrachten Sie das folgende Beispiel in Set-Builder-Notation.
oder oft
Dies kann gelesen werden, " ist der Satz aller Zahlen "2 Mal " SO DASS ist ein Element oder Mitglied des Satzes von natürliche Zahlen (), UND Quadrat ist größer als . "
Die kleinste natürliche Zahl, x = 1, erfüllt den Zustand x nicht2> 3 (der Zustand 12> 3 ist falsch.2> 3) wie jede andere natürliche Zahl. Somit besteht x aus 2, 3, 4, 5 ... seit dem Satz S besteht aus allen Zahlen "2 mal x". Es wird durch s = {4, 6, 8, 10, ...} angegeben. S ist mit anderen Worten die Menge aller sogar Zahlen von größer als 2.
In dieser kommentierten Version des Beispiels:
- ist die Variable, die Mitglieder eines Eingabessatzes darstellt.
- repräsentiert den Eingangssatz, in diesem Beispiel der Satz natürlicher Zahlen
- ist ein Prädikat Ausdruck, der als Filter für Mitglieder des Eingangssatzes fungiert.
- ist ein Ausgangsausdruck, der Mitglieder des neuen Satzes von Mitgliedern des Eingangssatzes erzeugt, die den Prädikatausdruck erfüllen.
- Zahnspangen zeigen, dass das Ergebnis ein Satz ist
- Die vertikale Balken wird als "so dass" gelesen. Die Bar und der Dickdarm ":" werden austauschbar verwendet.
- Kommas trennen die Prädikate und können als "und" gelesen werden.
Ein Listenverständnis hat die gleichen syntaktischen Komponenten, um die Erzeugung einer Liste in der Reihenfolge einer Eingabe darzustellen aufführen oder Iterator:
- Eine Variable, die Mitglieder einer Eingabeliste darstellt.
- Eine Eingabeliste (oder Iterator).
- Ein optionaler Prädikatausdruck.
- Und ein Ausgangsausdruck, das Mitglieder der Ausgabeliste von Mitgliedern des iterablen Eingangs erzeugt, die das Prädikat erfüllen.
Die Reihenfolge der Erzeugung der Mitglieder der Ausgabeliste basiert auf der Reihenfolge der Elemente in der Eingabe.
Im Haskells Listenverständnis-Syntax, dieses Set-Builder-Konstrukt würde ähnlich geschrieben wie:
s = [ 2*x | x <- [0..], x^2 > 3 ]
Hier die Liste [0 ..]
repräsentiert , x^2> 3
repräsentiert das Prädikat und 2*x
repräsentiert den Ausgangsausdruck.
Listenverständnisse geben Ergebnisse in einer definierten Reihenfolge (im Gegensatz zu den Mitgliedern von Sets). und listen Verständnisse auf generieren Die Mitglieder einer Liste in der Reihenfolge, anstatt die gesamte Liste zu erstellen, ermöglicht dies beispielsweise die vorherige Haskell -Definition der Mitglieder einer unendlichen Liste.
Geschichte
Das Vorhandensein verwandter Konstrukte lehnen die Verwendung des Begriffs "Listenverständnis" vor. Das Setl Die Programmiersprache (1969) hat ein Set -Formationskonstrukt, das den Listenverständnissen ähnelt. Z. B. druckt dieser Code alle Primzahlen von 2 nach N:
print ([n in [2..n] | forall m in {2..n - 1} | n mod m> 0]);
Das Computeralgebra -System AXIOM (1973) hat ein ähnliches Konstrukt wie Prozesse Ströme.
Die erste Verwendung des Begriffs "Verständnis" für solche Konstrukte war in Rod Burstall und John DarlingtonBeschreibung ihrer funktionalen Programmiersprache Npl ab 1977. In seiner retrospektiven "einige Geschichte funktionaler Programmiersprachen",[1] David Turner erinnert sich:
NPL wurde in POP2 von Burstall implementiert und für Darlingtons Arbeit zur Programmtransformation (Burstall & Darlington 1977) verwendet. Die Sprache war erster Ordnung, stark (aber nicht polymorph) typisiert, rein funktionell, Call-by-Wert. Es hatte auch "Ausdrücke", z.
setofeven (x) <= <: x: x in x & sogar (x):>}}
In einer Fußnote, die dem Begriff "Listenverständnis" angeschlossen ist, stellt Turner auch fest
Ich nannte diese diese ursprünglich ZF Ausdrücke, ein Verweis auf Zermelo-Frankel-Set-Theorie-es war es Phil Wadler wer prägte den besseren Begriff Listenverständnis.
Die Arbeit von Burstall und Darlington mit NPL beeinflussten in den 1980er Jahren viele funktionale Programmiersprachen, aber nicht alle enthaltene Listenverständnisse. Eine Ausnahme war Turners einflussreicher, reiner, fauler und funktionaler Programmiersprache Miranda, veröffentlicht 1985. Die anschließend entwickelte standardmäßige reine faule funktionale Sprache Haskell Enthält viele Merkmale von Miranda, einschließlich Listenverständnissen.
Verständnisse wurden als Abfragenotation für Datenbanken vorgeschlagen[2] und wurden in der implementiert KLEISLI Datenbankabfragesprache.[3]
Beispiele in verschiedenen Programmiersprachen
Ähnliche Konstrukte
Monad -Verständnis
In Haskell, a Monad -Verständnis ist eine Verallgemeinerung des Listenverständnisses für andere Monaden in der funktionalen Programmierung.
Verständnis festlegen
Version 3.x und 2.7 der Python -Sprache führt Syntax für ein einstellen Verständnis. Ähnlich in Form von Verständnissen werden Set -Verständnisse Python -Sets anstelle von Listen generieren.
>>> s = {v zum v in 'ABCDABCD' wenn v nicht in 'CB'} >>> drucken(s) {'EIN', 'D'} >>> Typ(s) <Klasse 'einstellen'> >>>
Schläger SET -Verständnisse generieren Schläger -Sets anstelle von Listen.
(für/set [v "ABCDABCD"] #:wenn nicht (Mitglied v (String-> Liste "CB"))) v))
Wörterbuchverständnis
Version 3.x und 2.7 der Python -Sprache führten eine neue Syntax für ein Wörterbuch Verständnisse, ähnlich in Form zur Auflistung von Verständnissen, aber Python erzeugt Diktate anstelle von Listen.
>>> s = {Schlüssel: val zum Schlüssel, val in aufzählen('A B C D') wenn val nicht in 'CB'} >>> s {0: 'EIN', 3: 'D'} >>>
Schläger -Hash -Tabellenverständnisse erzeugen Schläger -Hash -Tabellen (eine Implementierung des Schlägerwörterbuchstyps).
(für/hash ([[[val Schlüssel) (im Indexed "A B C D")] #:wenn nicht (Mitglied val (String-> Liste "CB"))) (Werte Schlüssel val))
Parallellistenverständnis
Das Glasgow Haskell Compiler hat eine Erweiterung genannt Parallellistenverständnis (auch bekannt als Reißverschluss) Das ermöglicht mehrere unabhängige Zweige von Qualifikatoren innerhalb der List -Verständnissyntax. Während die durch Kommas getrennten Qualifikationen abhängig sind ("verschachtelt"), werden Qualifikationsspiele, die durch Rohre getrennt sind Reißverschluss).
- Regelmäßiges Listenverständnis a = [(x,y) | x <- [1..5], y <- [3..5]] - [(1,3), (1,4), (1,5), (2,3), (2,4) ... - Verständnis für das Listenverständnis b = [(x,y) | (x,y) <- Postleitzahl [1..5] [3..5]] - [(1,3), (2,4), (3,5)] - Verständnis des Parallellisten c = [(x,y) | x <- [1..5] | y <- [3..5]] - [(1,3), (2,4), (3,5)]
Die Standardbibliothek des Schlägers umfasst die Standardbibliothek enthält parallele und verschachtelte Versionen ihrer Verständnisse, die durch "für" vs "für*" im Namen unterschieden werden. Beispielsweise erstellen die Vektorverständnisse "für/Vektor" und "für*/Vektor" Vektoren durch parallele und verschachtelte Iteration über Sequenzen. Im Folgenden finden Sie den Schlägercode für die Beispiele für die Haskell -Liste Verständnis.
> (für*/list [x (im Bereich 1 6)] [y (im Bereich 3 6)])) (aufführen x y)) '((1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 3) (3 4) (3 5) (4 3) (4 4) (4 5) (5 3) (5 4) (5 5)) > (für/liste [x (im Bereich 1 6)] [y (im Bereich 3 6)])) (aufführen x y)) '((1 3) (2 4) (3 5))
In Python konnten wir wie folgt tun:
# Regules Listenverständnis >>> a = [(x, y) zum x in Angebot(1, 6) zum y in Angebot(3, 6)] [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), ... # Parallel/Reißverständnis für das Listen >>> b = [x zum x in Postleitzahl(Angebot(1, 6), Angebot(3, 6))]] [(1, 3), (2, 4), (3, 5)]
In Julia können praktisch die gleichen Ergebnisse wie folgt erzielt werden:
# Regelmäßiges Array -Verständnis >>> a = [(x, y) zum x in 1:5 zum y in 3:5] # Parallel/Reißverständnis für das Array >>> b = [x zum x in Postleitzahl(1:3, 3:5)]
Mit dem einzigen Unterschied, dass wir in Julia anstelle von Listen Arrays haben.
XQuery und Xpath
Wie bei der ursprünglichen NPL -Verwendung handelt es sich um grundsätzlich Datenbankzugriffssprachen.
Dies macht das Verständniskonzept wichtiger, da es rechnerisch nicht realisierbar ist, die gesamte Liste abzurufen und darauf zu arbeiten (die anfängliche "gesamte Liste" kann eine gesamte XML -Datenbank sein).
In Xpath den Ausdruck:
/Bibliothek/Buchen//Absatz[@Stil="Erstkapitel"]
wird konzeptionell als eine Reihe von "Schritten" bewertet, wobei jeder Schritt eine Liste erstellt und der nächste Schritt eine Filterfunktion für jedes Element in der Ausgabe des vorherigen Schritts anwendet.[4]
In XQuery ist Full XPath verfügbar, aber aber Flor Aussagen werden ebenfalls verwendet, was ein leistungsfähigeres Verständniskonstrukt ist.[5]
zum $b in //Buchen wo $b[@pages < 400] Sortieren nach $b//Titel Rückkehr {$b//Titel} {(($Buchen//Absatz) [1]}
Hier wird das XPath // Buch bewertet, um eine Sequenz (auch bekannt als Liste) zu erstellen. Die WHERE -Klausel ist ein funktionaler "Filter", die Reihenfolge nach dem Ergebnis und die
XML Snippet ist eigentlich ein Anonyme Funktion Das erstellt/transformiert XML für jedes Element in der Sequenz unter Verwendung des in anderen funktionalen Sprachen gefundenen Ansatzes "MAP".
In einer anderen funktionalen Sprache kann die obige FLWOR -Anweisung so implementiert werden:
Karte( Newxml(Shortbook, Newxml(Titel, $1.Titel), Newxml(FirstPara, $1 ...)) Filter( lt($1.Seiten, 400), XPath(//Buchen) ) )
Linq in C#
C# 3.0 hat eine Gruppe verwandter Funktionen namens namens Linq, was eine Reihe von Abfrageberatoren für die Manipulation von Objektaufzählungen definiert.
var s = Aufzählbar.Bereich(0, 100).Wo(x => x * x > 3).Auswählen(x => x * 2);
Es bietet auch eine alternative Verständnissyntax, die an SQL erinnert:
var s = aus x in Aufzählbar.Bereich(0, 100) wo x * x > 3 auswählen x * 2;
LINQ bietet eine Fähigkeit über typische Implementierungen des Listenverständnisses. Wenn das Wurzelobjekt des Verständnisses das implementiert IQueryable
Schnittstelle, anstatt nur die geketteten Methoden des Verständnisses auszuführen, werden die gesamte Folge von Befehlen in eine konvertiert Zusammenfassung Syntaxbaum (AST) Objekt, das an das iQueryable -Objekt übergeben wird, um zu interpretieren und auszuführen.
Dies ermöglicht unter anderem die IQueryable zu
- Schreiben Sie ein inkompatibles oder ineffizientes Verständnis um
- Übersetzen Sie den AST in eine andere Abfragesprache (z. B. SQL) für die Ausführung
C ++
C ++ verfügt über keine Sprachfunktionen, die die Listenverständnisse jedoch jedoch direkt unterstützt Bedienerüberlastung (z. B. Überlastung |
, >>
, >> =
) wurde erfolgreich verwendet, um expressive Syntax für die "eingebettete" Abfrage bereitzustellen Domänenspezifische Sprachen (DSL). Alternativ können Listenverständnisse mit dem konstruiert werden Löschen Sie die Idiom So wählen Sie Elemente in einem Container und im STL -Algorithmus for_each aus, um sie zu transformieren.
#enthalten #enthalten
#enthalten Verwendung Namespace std; Schablone<Klasse C, Klasse P, Klasse T> C begreifen(C&& Quelle, Const P& Prädikat, Const T& Transformation) { // Ziel initialisieren C d = nach vorne<C>(Quelle); // Filterelemente d.löschen(remove_if(Start(d), Ende(d), Prädikat), Ende(d)); // Transformation anwenden für jeden(Start(d), Ende(d), Transformation); Rückkehr d; } int hauptsächlich() { aufführen<int> Angebot(10); // Range ist eine Liste von 10 Elementen, alle Null Jota(Start(Angebot), Ende(Angebot), 1); // Bereich enthält jetzt 1, 2, ..., 10 aufführen<int> Ergebnis = begreifen( Angebot, [] (int x) { Rückkehr x * x <= 3; }, [] (int &x) { x *= 2; }); // Ergebnis enthält jetzt 4, 6, ..., 20 }
Es gibt einige Anstrengungen, um C ++ mit Listenabschlusskonstrukten/Syntax zu liefern, ähnlich der Set Builder-Notation.
- Im Schub. Bereich [1] Bibliothek Es gibt einen Begriff von Adaptern [2] Dies kann auf jede Reichweite angewendet werden und Filterung, Transformation usw. mit dieser Bibliothek aussehen, wie das ursprüngliche Haskell -Beispiel aussehen würde (mit Boost.lambda [3] für anonyme Filter- und Transformationsfunktionen) (Vollständiges Beispiel):
counting_range(1,10) | gefiltert( _1*_1 > 3 ) | transformiert(ret<int>( _1*2 ))
- Dies[6] Die Implementierung verwendet ein Makro und überlastet den << Operator. Es bewertet jeden Ausdruck, der in einem 'if' gilt, und es kann ein variabler Name gewählt werden. Es ist nicht Threadsafe, jedoch. Verwendungsbeispiel:
aufführen<int> N; aufführen<doppelt> S; zum (int i = 0; i < 10; i++) N.push_back(i); S << list_compredesion(3.1415 * x, x, N, x * x > 3)
- Dies[7] Die Implementierung bietet Kopf-/Schwanzschneide mit Klassen und Bedienerüberladungen sowie der | Bediener für Filterlisten (Verwendung von Funktionen). Verwendungsbeispiel:
bool eben(int x) { Rückkehr x % 2 == 0; } bool x2(int &x) { x *= 2; Rückkehr Stimmt; } aufführen<int> l, t; int x, y; zum (int i = 0; i < 10; i++) l.push_back(i); (x, t) = l | x2; (t, y) = t; t = l < 9; t = t < 7 | eben | x2;
- Sprache für eingebettete Abfragen und Durchfahrten (Leesa[8]) ist ein eingebettetes DSL in C ++, das X-path-ähnliche Abfragen mit Operatorüberladung implementiert. Die Abfragen werden auf reich typisierten XML-Bäumen ausgeführt, die unter Verwendung von XML-zu-C ++-Bindung von einem XSD erhalten wurden. Es gibt absolut keine String -Codierung. Sogar die Namen der XML -Tags sind Klassen, und daher gibt es keine Möglichkeit für Tippfehler. Wenn ein Leesa -Ausdruck einen falschen Pfad bildet, der im Datenmodell nicht vorhanden ist, lehnt der C ++ - Compiler den Code ab.
Betrachten Sie einen Katalog XML.
Weiler 9.99 William Shakespeare England ... ...
Leesa bietet >>
Für XPaths / Separator. XPaths // Separator, das Intermediate -Knoten im Baum "überspringt", wird in LEESA unter Verwendung einer sogenannten strategischen Programmierung implementiert. Im folgenden Beispiel sind Catalog_, Book_, Author_ und Name_ Instanzen von Katalog-, Buch-, Autor- und Namensklassen.
// Äquivalent X-Path: "Katalog/Buch/Autor/Name" std::Vektor<Name> Author_names = auswerten(Wurzel, Katalog_ >> Buchen_ >> Autor_ >> Name_); // äquivalente X-Path: "Katalog // Name" std::Vektor<Name> Author_names = auswerten(Wurzel, Katalog_ >> Nachkommen von(Katalog_, Name_)); // Äquivalent X-Path: "Katalog // Autor [Country ==" England "]" std::Vektor<Name> Author_names = auswerten(Wurzel, Katalog_ >> Nachkommen von(Katalog_, Autor_) >> Auswählen(Autor_, [] (Const Autor & a) { Rückkehr a.Land() == "England"; }) >> Name_);
Siehe auch
- Set-Builder-Notation
- Das AUSWÄHLEN Aussage zusammen mit seiner aus und wo Klauseln in Sql
Notizen und Referenzen
- ^ Turner, David (2012). "Einige Geschichte funktionaler Programmiersprachen" (PDF). Internationales Symposium über Trends in der funktionellen Programmierung, Springer, Berlin, Heidelberg. S. 1–20.
- ^ Verfassungen, eine Abfragenotation für DBPLs
- ^ Die funktionalen Eingeweide des Keisli -Query -Systems
- ^ "2.1 Standortschritte". XML -Pfadsprache (XPath). W3c. 16. November 1999. archiviert von das Original am 9. Dezember 2012. Abgerufen 24. Dezember 2008.
- ^ "XQuery Flor Expressions". W3schools. Archiviert von das Original Am 2011-10-08.
- ^ "Einvariable Listenverständnis in C ++ unter Verwendung von Präzessor-Makros". Archiviert von das Original Am 2011-08-21. Abgerufen 2011-01-09.
- ^ "C ++ - List -Verständnis". Archiviert von das Original Am 2017-07-07. Abgerufen 2011-01-09.
- ^ "Sprache für eingebettete Abfrage und Traversal (Leesa)".
- Listenverständnis Im kostenlosen Online-Wörterbuch von Computing, Herausgeber Denis Howe.
- Wadler, Philip (1990). "Monaden verstehen". Proceedings der ACM -Konferenz von 1990 über LISP- und Funktionsprogrammierung, schön.
Externe Links
- SQL-ähnliche Set-Operationen mit Listenverständnis-Einzeilern in der Python -Kochbuch
- Diskussion zu Listenfindungen in Schema und verwandten Konstrukten
- Listen Sie die Verständnisse über Sprachen hinweg auf
Axiom
Clojure
Common Lisp
- Implementierung eines Lisp -Verständnis -Makros von Guy Lapalme
Haskell
- Der Haskell 98 -Bericht, Kapitel 3.11 Auflistung von Verständnissen.
- Das glorreiche Glasgow Haskell Compilation System Benutzerhandbuch, Kapitel 7.3.4 Parallele List -Verständnis.
- Der Hut 98 -Benutzerhandbuch, Kapitel 5.1.2 Parallele List-Verständnis (a.k.a. Reißverschluss).
Ocaml
Python
- Das Python -Tutorial, Listen Sie Verständnisse auf.
- Python -Sprachreferenz, Liste wird angezeigt.
- Python Enhancement Vorschlag PEP 202: Auflisten Verständnisse auflisten.
- Python -Sprachreferenz, Generatorausdrücke.
- Python Enhancement Vorschlag PEP 289: Generatorausdrücke.