A list comprehension is a syntactic construct available in some programming languages for creating a list based on existing lists. It follows the form of the mathematical set-builder notation (set comprehension) as distinct from the use of map and filter functions.
Consider the following example in mathematical set-builder notation.
S=\{2 ⋅ x\midx\inN, x2>3\}
S=\{2 ⋅ x:x\inN, x2>3\}
This can be read, "
S
x
x
N
x
3
The smallest natural number, x = 1, fails to satisfy the condition x2>3 (the condition 12>3 is false) so 2 ·1 is not included in S. The next natural number, 2, does satisfy the condition (22>3) as does every other natural number. Thus x consists of 2, 3, 4, 5... Since the set consists of all numbers "2 times x" it is given by S = . S is, in other words, the set of all even numbers greater than 2.
In this annotated version of the example:
S=\{\underbrace{2 ⋅ x}\color{Violet{outputexpression
x
N
x2>3
2 ⋅ x
\{\}
\mid
,
A list comprehension has the same syntactic components to represent generation of a list in order from an input list or iterator:
The order of generation of members of the output list is based on the order of items in the input.
In Haskell's list comprehension syntax, this set-builder construct would be written similarly, as:
Here, the list [0..]
represents
N
x^2>3
represents the predicate, and 2*x
represents the output expression.List comprehensions give results in a defined order (unlike the members of sets); and list comprehensions may generate the members of a list in order, rather than produce the entirety of the list thus allowing, for example, the previous Haskell definition of the members of an infinite list.
The existence of related constructs predates the use of the term "List Comprehension". The SETL programming language (1969) has a set formation construct which is similar to list comprehensions. E.g., this code prints all prime numbers from 2 to : print([n in [2..N] | forall m in | n mod m > 0]);The computer algebra system AXIOM (1973) has a similar construct that processes streams.
The first use of the term "comprehension" for such constructs was in Rod Burstall and John Darlington's description of their functional programming language NPL from 1977. In his retrospective "Some History of Functional Programming Languages",[1] David Turner recalls:
}}
In a footnote attached to the term "list comprehension", Turner also notes
Burstall and Darlington's work with NPL influenced many functional programming languages during the 1980s, but not all included list comprehensions. An exception was Turner's influential, pure, lazy, functional programming language Miranda, released in 1985. The subsequently developed standard pure lazy functional language Haskell includes many of Miranda's features, including list comprehensions.
Comprehensions were proposed as a query notation for databases[2] and were implemented in the Kleisli database query language.[3]
See main article: Comparison of programming languages (list comprehension).
In Haskell, a monad comprehension is a generalization of the list comprehension to other monads in functional programming.
The Python language introduces syntax for set comprehensions starting in version 2.7. Similar in form to list comprehensions, set comprehensions generate Python sets instead of lists.
Racket set comprehensions generate Racket sets instead of lists.
The Python language introduced a new syntax for dictionary comprehensions in version 2.7, similar in form to list comprehensions but which generate Python dicts instead of lists.
Racket hash table comprehensions generate Racket hash tables (one implementation of the Racket dictionary type).
The Glasgow Haskell Compiler has an extension called parallel list comprehension (also known as zip-comprehension) that permits multiple independent branches of qualifiers within the list comprehension syntax.Whereas qualifiers separated by commas are dependent ("nested"), qualifier branches separated by pipes are evaluated in parallel (this does not refer to any form of multithreadedness: it merely means that the branches are zipped).
-- parallel list comprehensionc = [(x,y) | x <- [1..5] | y <- [3..5]]-- [(1,3),(2,4),(3,5)]
Racket's comprehensions standard library contains parallel and nested versions of its comprehensions, distinguished by "for" vs "for*" in the name. For example, the vector comprehensions "for/vector" and "for*/vector" create vectors by parallel versus nested iteration over sequences. The following is Racket code for the Haskell list comprehension examples.
In Python, we could do as follows:
In Julia, practically the same results can be achieved as follows:
>>> a = [(x, y) for x in 1:5 for y in 3:5]
>>> b = [x for x in zip(1:3, 3:5)]with the only difference that instead of lists, in Julia, we have arrays.
Like the original NPL use, these are fundamentally database access languages.
This makes the comprehension concept more important, because it is computationally infeasible to retrieve the entire list and operate on it (the initial 'entire list' may be an entire XML database).
In XPath, the expression:
In XQuery, full XPath is available, but FLWOR statements are also used, which is a more powerful comprehension construct.[5]
So, in another functional language the above FLWOR statement may be implemented like this:
C# 3.0 has a group of related features called LINQ, which defines a set of query operators for manipulating object enumerations.
It also offers an alternative comprehension syntax, reminiscent of SQL:
LINQ provides a capability over typical list comprehension implementations. When the root object of the comprehension implements the IQueryable
interface, rather than just executing the chained methods of the comprehension, the entire sequence of commands are converted into an abstract syntax tree (AST) object, which is passed to the IQueryable object to interpret and execute.
This allows, amongst other things, for the IQueryable to
C++ does not have any language features directly supporting list comprehensions but operator overloading (e.g., overloading |
, >>
, >>=
) has been used successfully to provide expressive syntax for "embedded" query domain-specific languages (DSL). Alternatively, list comprehensions can be constructed using the erase-remove idiom to select elements in a container and the STL algorithm for_each to transform them.
using namespace std;
template
int mainThere is some effort in providing C++ with list-comprehension constructs/syntax similar to the set builder notation.
counting_range(1,10) | filtered(_1*_1 > 3) | transformed(ret
for (int i = 0; i < 10; i++) N.push_back(i);
S << list_comprehension(3.1415 * x, x, N, x * x > 3)
list
for (int i = 0; i < 10; i++) l.push_back(i);
(x, t) = l | x2;(t, y) = t;
t = l < 9;t = t < 7 | even | x2;
>>
for XPath's / separator. XPath's // separator that "skips" intermediate nodes in the tree is implemented in LEESA using what's known as Strategic Programming. In the example below, catalog_, book_, author_, and name_ are instances of catalog, book, author, and name classes, respectively.
// Equivalent X-Path: "catalog//name"std::vector
// Equivalent X-Path: "catalog//author[country=="England"]"std::vector