Haskell · Syntax · Listen
List Comprehensions in Haskell, erklärt
Eines der ersten Dinge, die Haskell elegant machen, ist die List Comprehension: eine knappe Art, aus bestehenden Listen eine neue Liste zu bauen, in Anlehnung an die mathematische Mengenschreibweise, an die Sie sich vielleicht aus der Schule erinnern. Dieser Leitfaden erklärt die Syntax, mehrere Generatoren, Guards und den Bezug zwischen Comprehensions und map sowie filter.
Die Grundsyntax
Eine List Comprehension hat die Form [ output | generator, condition ]. Lesen Sie den senkrechten Strich als „sodass“:
-- the squares of 1 to 10
squares = [x*x | x <- [1..10]]
-- [1,4,9,16,25,36,49,64,81,100] Hier ist x <- [1..10] ein Generator: Er zieht jedes x aus der Liste [1..10], und der Teil vor dem Strich, x*x, ist der Ausgabeausdruck, der auf jedes Element angewendet wird.
Guards hinzufügen (Filtern)
Ein Guard ist eine boolesche Bedingung, die nur die Elemente behält, die sie erfüllen:
-- even numbers from 1 to 20, doubled
result = [x*2 | x <- [1..20], even x]
-- [4,8,12,16,20,24,28,32,36,40] Sie können mehrere Guards kombinieren, durch Kommas getrennt; alle müssen wahr sein, damit ein Element aufgenommen wird.
Mehrere Generatoren
Mit mehr als einem Generator iteriert die Comprehension über jede Kombination (wie verschachtelte Schleifen), der Reihe nach:
-- all pairs from two small lists
pairs = [(x, y) | x <- [1,2,3], y <- ['a','b']]
-- [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')] Der am weitesten rechts stehende Generator variiert am schnellsten. Sie können auch einen späteren Generator von einem früheren abhängig machen — etwa indem Sie y aus [x..10] ziehen.
Ihr Bezug zu map und filter
Eine Comprehension ist im Wesentlichen map und filter in einer einzigen lesbaren Form. Diese sind gleichwertig:
[x*2 | x <- xs, even x]
map (*2) (filter even xs) Nehmen Sie, was sich im jeweiligen Fall am besten liest. Comprehensions glänzen, wenn Sie mehrere Generatoren oder mehrere Guards haben; map/filter lassen sich gut in point-free-Pipelines verketten. Weil Haskell lazy ist, berechnet eine Comprehension über eine unendliche Liste wie [1..] nur die Elemente, die Sie tatsächlich verbrauchen.
FAQ
Was ist ein Generator in einer List Comprehension? Der Teil x <- xs: Er zieht jeden Wert von x aus der Liste xs, um den Ausgabeausdruck zu speisen.
Was ist ein Guard? Eine boolesche Bedingung (wie even x), die nach einem Komma steht; nur die Elemente, für die sie wahr ist, werden behalten.
Kann ich mehrere Generatoren verwenden? Ja — die Comprehension erzeugt jede Kombination, wobei der am weitesten rechts stehende Generator am schnellsten variiert, wie verschachtelte Schleifen.
Sind Comprehensions einfach map und filter? Konzeptionell ja für die einfachen Fälle; Comprehensions sind oft besser lesbar mit mehreren Generatoren oder Guards, während map/filter sich gut in Pipelines verketten lassen.
Zur Sprache hinter der Syntax sehen Sie was Haskell ist; Comprehensions sind eine der Eigenschaften, die es knapp und ausdrucksstark machen.