|
|
Line 1: |
Line 1: |
| A '''list comprehension''' is a [[Syntax of programming languages|syntactic]] construct available in some [[programming language]]s for creating a list based on existing [[list (computing)|lists]]. It follows the form of the mathematical ''[[set-builder notation]]'' (''set comprehension'') as distinct from the use of [[Map (higher-order function)|map]] and [[Filter (higher-order function)|filter]] functions.
| | Roberto is [http://www.alexa.com/search?q=what%27s+written&r=topsites_index&p=bigtop what's written] concerning his birth certificate rather he never really preferred that name. Managing people is without question where his primary financial comes from. Base jumping is something that he or she is been doing for years. Massachusetts has always been his everyday living place and his spouse and [http://www.children.com/ children] members loves it. Go for his website to come across out more: http://prometeu.net<br><br>Feel free to visit my website: [http://prometeu.net Clash Of Clans Cheat Gems] |
| | |
| ==Overview==
| |
| Consider the following example in [[set-builder notation]].
| |
| | |
| :<math>S=\{\,2\cdot x\mid x \in \mathbb{N},\ x^2>3\,\}</math>
| |
| | |
| This can be read, "<math>S</math> is the set of all numbers "2 times <math>x</math>" where <math>x</math> is an item in the set of [[natural number]]s (<math>\mathbb{N}</math>), for which <math>x</math> squared is greater than <math>3</math>."
| |
| | |
| In this annotated version of the example:
| |
| :<math>S=\{\,\underbrace{2\cdot x}_{\color{Violet}\text{output expression}}\mid \underbrace{x}_{\color{Violet}\text{variable}} \in \underbrace{\mathbb{N}}_{\color{Violet}\text{input set}},\ \underbrace{x^2>3}_{\color{Violet}\text{predicate}}\,\}</math>
| |
| * <math>x</math> is the variable representing members of an input set.
| |
| * <math>\mathbb{N}</math> represents the input set, which in this example is the set of natural numbers
| |
| * <math>x^2>3</math> is a [[Predicate (logic)|predicate]] expression acting as a filter on members of the input set.
| |
| * <math>2\cdot x</math> is an output expression producing members of the new set from members of the input set that satisfy the predicate expression.
| |
| * <math>\{\}</math> brackets contain the expression
| |
| * <math>\mid</math> <math>,</math> the vertical bar and the comma are separators.
| |
| | |
| A list comprehension has the same syntactic components to represent generation of a list in order from an input [[List (computing)|list]] or [[iterator]]:
| |
| * A variable representing members of an input list.
| |
| * An input list (or iterator).
| |
| * An optional predicate expression.
| |
| * And an output expression producing members of the output list from members of the input iterable that satisfy the predicate.
| |
| The order of generation of members of the output list is based on the order of items in the input.
| |
| | |
| In [[Haskell (programming language)|Haskell's]] list comprehension syntax, this set-builder construct would be written similarly, as:
| |
| <source lang="haskell">
| |
| s = [ 2*x | x <- [0..], x^2 > 3 ]
| |
| </source>
| |
| | |
| Here, the list <code>[0..]</code> represents <math>\mathbb{N}</math>, <code>x^2>3</code> represents the predicate, and <code>2*x</code> represents the output expression.
| |
| | |
| List comprehensions give results in a defined order (unlike the members of sets); and list comprehensions may [[Generator (computer science)|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.
| |
| | |
| ==History==
| |
| | |
| The [[SETL programming language]] (later 1960s) had a set formation construct, and the [[computer algebra system]] [[Axiom (computer algebra system)|AXIOM]] (1973) has a similar construct that processes [[stream (computing)|stream]]s,
| |
| but 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 programming language|NPL]] from 1977.
| |
| | |
| [[Smalltalk]] block context messages which constitute list comprehensions have been in that language since at least Smalltalk-80.
| |
| | |
| Burstall and Darlington's work with NPL influenced many functional programming languages during the 1980s, but not all included list comprehensions. An exception was the influential pure lazy functional programming language [[Miranda programming language|Miranda]], which was released in 1985. The subsequently developed standard pure lazy functional language [[Haskell programming language|Haskell]] includes many of Miranda's features, including list comprehensions.
| |
| | |
| Comprehensions were proposed as a query notation for databases<ref>[http://portal.acm.org/citation.cfm?coll=GUIDE&dl=GUIDE&id=135271 Comprehensions, a query notation for DBPLs<!-- Bot generated title -->]</ref> and were implemented in the ''Kleisli'' database query language.<ref>[http://portal.acm.org/citation.cfm?id=351241&dl=ACM&coll=portal The functional guts of the Kleisli query system<!-- Bot generated title -->]</ref>
| |
| | |
| == Examples in different programming languages ==
| |
| | |
| {{main|Comparison of programming languages (list comprehension)}}
| |
| | |
| The following provides a few examples of specific syntax used in programming languages.
| |
| | |
| Although the original example denotes an infinite list, few languages can express that, so in some of those cases we show how to take a subset of <math>\{0, 1, ..., 100\}</math> rather than a subset of <math>\mathbb{N}</math>.
| |
| | |
| === B-Prolog ===
| |
| {{further2|[[BProlog]]}}
| |
| | |
| <source lang="prolog">
| |
| L @= [Y : X in 1..100, [Y], (X*X>3, Y is 2*X)]
| |
| </source>
| |
| | |
| A list of the form <code>[T : E1 in D1, ..., En in Dn, LocalVars, Goal]</code> is interpreted as a list comprehension in calls to <code>@=/2</code> and constraints. A list comprehension is translated into a foreach construct with an accumulator.
| |
| | |
| === Ceylon ===
| |
| {{further2|[[Ceylon Project]]}}
| |
| | |
| <pre>
| |
| { for (x in 0..100) if ( x**2 > 3) x * 2 }
| |
| </pre>
| |
| | |
| === Clojure ===
| |
| {{further2|[[Clojure]]}}
| |
| | |
| Clojure generates infinite lazy sequences (similar to Haskell's lazy lists or Python's generators). Use '''take''' to get the first N results from the infinite sequence.
| |
| | |
| <source lang="lisp">
| |
| (take 20 (for [x (range) :when (> (* x x) 3)] (* 2 x)))
| |
| ;; ⇒ (4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42)
| |
| </source>
| |
| | |
| === CoffeeScript ===
| |
| {{further2|[[CoffeeScript]]}}
| |
| | |
| CoffeeScript brings pretty list comprehensions to JavaScript.
| |
| | |
| <source lang="CoffeeScript">
| |
| (x * 2 for x in [0..20] when x*x > 3)
| |
| </source>
| |
| | |
| === Common Lisp ===
| |
| {{further2|[[Common Lisp]]}}
| |
| | |
| List comprehensions can be expressed with the <code>loop</code> macro's <code>collect</code> keyword. Conditionals are expressed with <code>if</code>, as follows:
| |
| | |
| <source lang="lisp">
| |
| (loop for x from 0 to 100 if (> (* x x) 3) collect (* 2 x))
| |
| </source>
| |
| | |
| An infinite lazy sequence can be created in a variety of ways, such as the [[CLOS]] object system or a [[Generator (computer science)|yield]] macro.
| |
| | |
| === Elixir ===
| |
| {{further2|[[Elixir (programming language)|Elixir]]}}
| |
| | |
| The same example in Elixir:
| |
| <source lang="erlang">
| |
| S = lc x inlist Enum.to_list(0..100), x*x > 3, do: x*2
| |
| </source>
| |
| | |
| === Erlang ===
| |
| {{further2|[[Erlang (programming language)|Erlang]]}}
| |
| | |
| The same example in Erlang:
| |
| <source lang="erlang">
| |
| S = [2*X || X <- lists:seq(0,100), X*X > 3].</source>
| |
| | |
| === F# ===
| |
| {{further2|[[Fsharp|F#]]}}
| |
| | |
| The F# generator comprehension has the list comprehension syntax elements.
| |
| Generator comprehensions can be used to generate Lists, Sequences (lazy lists) and Arrays (not discussed here).
| |
| | |
| Generators are of the form <code>[for x in collection do ... yield expr]</code> for lists and <code>seq {for x in collection do ... yield expr}</code> for sequences.
| |
| For example:
| |
| | |
| <source lang="fsharp">
| |
| > seq { for x in 0..100 do
| |
| if x*x > 3 then yield 2*x } ;;
| |
| val it : seq<int> = seq [4; 6; 8; 10; ...]</source>
| |
| | |
| === Falcon ===
| |
| {{further2|[[Falcon (programming language)|Falcon]]}}
| |
| | |
| The "comp" generic method family provides wide support for comprehension. For example, the "mfcomp" method can be applied to an array:
| |
| <syntaxhighlight lang=falcon>
| |
| s = [].mfcomp( { i => if i*i > 3: return 2*i; return oob(1)}, [1:101] )
| |
| </syntaxhighlight>
| |
| Falcon can also use functional generators to provide input lists. For example, the following code uses a continuation to create a set of pairs.
| |
| <syntaxhighlight lang=falcon>
| |
| gen = Continuation( function( max, c )
| |
| i = 0
| |
| while i < max: c(++i)
| |
| return oob(0)
| |
| end )
| |
| data = [10,11,12]
| |
| s = Set().mfcomp( {x, y => x+y}, .[gen 3], data )
| |
| </syntaxhighlight>
| |
| Method "comp" was introduced in version 0.9.6, and methods "mcomp" and "mfcomp" in version 0.9.6.2.
| |
| | |
| === Groovy ===
| |
| {{further2|[[Groovy (programming language)|Groovy]]}}
| |
| | |
| Groovy supports list comprehension style expressions for any kind of Java Collection including lists, sets, and maps.
| |
| <source lang="groovy">
| |
| s = (1..100).grep { it ** 2 > 3 }.collect { it * 2 }
| |
| </source>
| |
| | |
| The "it" variable is shorthand for the implicit parameter to a closure. The above is equivalent to:
| |
| <source lang="groovy">
| |
| s = (1..100).grep { x -> x ** 2 > 3 }.collect { x -> x * 2 }
| |
| </source>
| |
| | |
| === Haskell ===
| |
| {{further2|[[Haskell (programming language)|Haskell]]}}
| |
| | |
| Please refer to the main example in the [[#Overview|overview]].
| |
| <source lang="haskell">
| |
| s = [ 2*x | x <- [0..], x^2 > 3 ]
| |
| </source>
| |
| | |
| Here, the list <code>[0..]</code> generates natural numbers one by one which get bound to variable <code>x</code>, <code>x^2>3</code> represents the predicate that either accepts or rejects a given variable's value, and <code>2*x</code> represents the result expression. There might be several generators and test predicates in one list compehension expression in Haskell, in effect defining nested loops, e.g.:
| |
| <source lang="haskell">
| |
| s = [ 2*x*y | x <- [0..], x^2 > 3, y <- [1,3..x], y^2 < 100-x^2]
| |
| -- for each x from 0 by 1:
| |
| -- if x^2 > 3:
| |
| -- for each y from 1 by 2 upto x:
| |
| -- if y^2 < 100 - x^2:
| |
| -- produce 2*x*y
| |
| </source>
| |
| The above expression becomes unproductive (''"stuck"'') at some point, when new '''''x'''''s keep being generated only to be rejected later on. This is so because any test can only reject a value it is given, not any future ones (there is no ''cut'' mechanism here, in [[Prolog]] terms - a generator in general might produce its values unordered, like e.g. the above expression itself). This can be dealt with using bounded list generators always or by enclosing a generator inside a <code>'''take'''</code> or <code>'''takeWhile'''</code> call, limiting the amount of generated values.
| |
| | |
| === Haxe ===
| |
| {{further2|[[Haxe]]}}
| |
| | |
| Haxe 3 released with array and map comprehension.<ref>http://haxe.org/manual/haxe3/features#array-comprehension</ref>
| |
| <source lang="haxe">
| |
| var s = [for(x in [0, 1, 2, 3, 4, 5, 6, 7]) if(x * x < 5) x];
| |
| </source>
| |
| However, Haxe 2's syntax required use of Lambda:
| |
| <source lang="haxe">
| |
| var a = [0, 1, 2, 3, 4, 5, 6, 7];
| |
| var s = Lambda.array(Lambda.filter(a, function(x) return x * x < 5));
| |
| </source>
| |
| | |
| === JavaScript 1.7 ===
| |
| | |
| JavaScript 1.7 has array comprehensions. The [[JavaScript engine]] of the popular [[Firefox browser]] from [[Mozilla Foundation]]---[[SpiderMonkey (JavaScript engine)|SpiderMonkey]]---supports them,<ref>https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Predefined_Core_Objects#Array_comprehensions</ref> for example,
| |
| <source lang="Javascript">
| |
| js> [2*x for each (x in [0,1,2,3,4,5,6,7]) if (x*x<5)]
| |
| [0, 2, 4]
| |
| </source>
| |
| | |
| The sequence of integers can be obtained by prototyping the Number object,
| |
| <source lang="Javascript">
| |
| Number.prototype.__iterator__=function(){for (var i=0; i<this; i++) yield i}
| |
| var s = [2*x for (x in 100) if (x*x<5)]
| |
| </source>
| |
| Or introducing a range function,
| |
| <source lang="Javascript">
| |
| var range = function(start,end){for (var i=start; i<=end; i++) yield i}
| |
| var s = [2*x for (x in range(0,100)) if (x*x<5)]
| |
| </source>
| |
| | |
| === Mathematica ===
| |
| {{further2|[[Mathematica]]}}
| |
| | |
| The Cases command with a <tt>RuleDelayed</tt> in the second argument provides a list comprehension mechanism:
| |
| | |
| <code>
| |
| s = Cases[Range[0,100], i_ /; i^2 > 3 :> 2i]</code>
| |
| Alternatively
| |
| | |
| <code>
| |
| Table[If[i^2 > 3, 2i, Unevaluated[]], {i, 0, 100}]
| |
| </code>
| |
| | |
| <code>
| |
| Do[If[i^2 > 3, Sow[2i]], {i, 0, 100}] // Reap
| |
| </code>
| |
| | |
| === OCaml ===
| |
| {{further2|[[OCaml]]}}
| |
| | |
| OCaml Batteries Included has uniform comprehension syntax for lists, arrays, enumerations (like streams), lazy lists (like lists but evaluated on-demand), sets, hashtables, etc.
| |
| | |
| Comprehension are of the form <code>[? expression | x <- enumeration ; condition; condition ; ... ?]</code>.
| |
| | |
| For instance,
| |
| <source lang="ocaml">
| |
| # [? 2 * x | x <- 0 -- max_int ; x * x > 3 ?];;
| |
| - : int Enum.t = <abstr>
| |
| </source>
| |
| or, to compute a list,
| |
| <source lang="ocaml">
| |
| # [? List: 2 * x | x <- 0 -- 5 ; x * x > 3 ?];;
| |
| - : int list = [4; 6; 8; 10]
| |
| </source>
| |
| or, to compute a set,
| |
| <source lang="ocaml">
| |
| # [? PSet: 2 * x | x <- 0 -- 5 ; x * x > 3 ?];;
| |
| - : int PSet.t = <abstr>
| |
| </source>
| |
| | |
| etc.
| |
| | |
| === Octave ===
| |
| [[GNU Octave]] can do list (vector) comprehensions in the form <code>(vector expression)(vector condition)</code>.
| |
| | |
| For example,
| |
| <source lang="octave">
| |
| octave:1> x=0:100; s=(2*x)(x.**2<5)
| |
| s =
| |
| 0 2 4</source>
| |
| | |
| === Perl 5 ===
| |
| {{further2|[[Perl 5]]}}
| |
| | |
| Perl 5 provides an alternate approach
| |
| | |
| <source lang="perl">
| |
| my @s = map { $_ * 2 } grep { $_ * $_ < 5 } (0..7);
| |
| </source>
| |
| | |
| === Perl 6 ===
| |
| {{further2|[[Perl 6]]}}
| |
| | |
| [[Perl 6]] provides more than one way to implement list comprehensions.
| |
| | |
| <source lang="perl6">
| |
| my @s = ($_ * 2 if $_ ** 2 > 3 for ^100);
| |
| </source>
| |
| | |
| Or, using [[Perl 6#Gather|gather]]:
| |
| | |
| <source lang="perl6">
| |
| my @s = gather { for ^100 { take 2 * $_ if $_ ** 2 > 3 } };
| |
| </source>
| |
| | |
| === Picat ===
| |
| | |
| <source lang="text">
| |
| [2*X : X in 1..100, X*X>3]
| |
| </source>
| |
| | |
| A list comprehension in [http://picat-lang.org Picat] takes the form <code>[T : E1 in D1, Cond1, ..., En in Dn, Condn]</code>. A list comprehension is compiled into a foreach loop, which is further compiled into a tail-recursive predicate.
| |
| | |
| === PowerShell ===
| |
| {{further2|[[PowerShell]]}}
| |
| | |
| <source lang="PowerShell">
| |
| 0..100 | Where {$_ * $_ -gt 3} | ForEach {$_ * 2}
| |
| </source>
| |
| | |
| === Pure ===
| |
| {{further2|[[Pure (programming language)|Pure]]}}
| |
| | |
| The same example in Pure:
| |
| s = [2*n | n=1..100; n*n > 3];
| |
| | |
| === Python ===
| |
| {{further2|[[Python syntax and semantics#Generators|Python syntax and semantics: Generators]]}}
| |
| | |
| The [[Python (programming language)|Python programming language]] has a corresponding syntax for expressing list comprehensions.
| |
| The near-equivalent in Python to the example above is as follows:
| |
| | |
| <source lang="python">
| |
| S = [2 * x for x in range(101) if x ** 2 > 3]
| |
| </source>
| |
| | |
| List comprehensions were introduced in Python version 2.0.<ref>{{cite web | url = http://www.python.org/dev/peps/pep-0202/ | title = PEP 202 – List Comprehensions | work = python.org | date = 2 October 2008 | first = Barry | last = Warsaw}}</ref>
| |
| | |
| === Racket ===
| |
| {{further2|[[Racket (programming language)|Racket]]}}
| |
| | |
| Racket provides functional versions of for-loops, which are essentially list comprehension syntax:
| |
| <source lang="scheme">
| |
| (for/list ([x (in-range 100)] #:when (> (* x x) 3))
| |
| (* 2 x))
| |
| </source>
| |
| The imperative <code>for</code> can also be used, combined with Racket's generator library to produce an infinite generator:
| |
| <source lang="scheme">
| |
| (require racket/generator)
| |
| (generator ()
| |
| (for ([x (in-naturals)] #:when (> (* x x) 3))
| |
| (yield (* 2 x))))
| |
| </source>
| |
| | |
| === Ruby ===
| |
| {{further2|[[Ruby (programming language)|Ruby]]}}
| |
| | |
| In the Ruby language you can use multiple ways to simulate this function, for example:
| |
| <source lang="Ruby">
| |
| (1..100).select{|x| x ** 2 > 3 }.collect{|x| 2 * x}
| |
| </source>
| |
| Or you can define your own method:
| |
| | |
| <source lang="Ruby">
| |
| module Enumerable
| |
| def comprehend(&block)
| |
| return self if block.nil?
| |
| collect(&block).compact
| |
| end
| |
| end
| |
| | |
| (1..100).comprehend {|x| 2 * x if x ** 2 > 3}
| |
| </source>
| |
| | |
| === Rust ===
| |
| {{further2|[[Rust (programming language)|Rust]]}}
| |
| | |
| The Rust language currently doesn't have a built-in support for list comprehensions but the functionality can be implemented as a macro:
| |
| <syntaxhighlight lang="text" line highlight="8">
| |
| macro_rules! compr(
| |
| ($o:expr : $v:ident <- $i:expr $(,$p:expr)+) =>
| |
| ($i.$(filtered(|&$v| { $p })).*.map(|&$v| { $o }));
| |
| ($o:expr : $v:ident <- $i:expr) =>
| |
| ($i.map(|&$v| { $o }))
| |
| )
| |
| | |
| let s = compr!(x * 2 : x <- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], x > 2);
| |
| </syntaxhighlight>
| |
| | |
| === Scala ===
| |
| {{further2|[[Scala (programming language)|Scala]]}}
| |
| | |
| Using a for-expression:
| |
| | |
| <source lang="scala">
| |
| val s = for (x <- Stream.from(0) if x*x > 3) yield 2*x
| |
| </source>
| |
| | |
| === Scheme ===
| |
| {{further2|[[Scheme (programming language)|Scheme]]}}
| |
| Although there is no standard list comprehension syntax in [[R5RS]], many implementations provide an extension for this. For example, in [[Chicken (Scheme implementation)|Chicken Scheme]]:
| |
| <source lang="scheme">
| |
| (require-extension list-of)
| |
| (list-of (* 2 x) (x range 0 101) (> (* x x) 3))
| |
| </source>
| |
| There is also a portable library SRFI/42 "Eager Comprehensions", which in particular includes list comprehensions:
| |
| <source lang="scheme">
| |
| (require srfi/42) ; example import into Racket Scheme
| |
| (list-ec (: x 101) (if (> (* x x) 3)) (* 2 x))
| |
| </source>
| |
| | |
| === SETL ===
| |
| {{further2|[[SETL]]}}
| |
| <source lang="html4strict">
| |
| s := {2*x : x in {0..100} | x**2 > 3 };
| |
| </source>
| |
| | |
| === Smalltalk ===
| |
| {{further2|[[Smalltalk]]}}
| |
| <source lang="smalltalk">
| |
| ((1 to: 100) select: [:x|x*x>3]) collect: [:x|2*x]
| |
| </source>
| |
| | |
| === SuperCollider ===
| |
| {{further2|[[SuperCollider]]}}
| |
| In SuperCollider list comprehensions are implemented as Routines, whose results can be collected with the message 'all'. A shortcut syntax is provided for defining list comprehensions, which internally translates to a routine.
| |
| <source lang="text">
| |
| all {: x * 2, x <- (1..100), x ** 2 > 3 }
| |
| </source>
| |
| | |
| === Visual Prolog ===
| |
| | |
| {{further2|[[Visual Prolog]]}}
| |
| | |
| <source lang="VisualProlog">S = [ 2*X || X = std::fromTo(1, 100), X^2 > 3 ]</source>
| |
| | |
| ==Similar constructs==
| |
| | |
| ===Monad comprehension===
| |
| In Haskell, a [[monads in functional programming#do-notation|monad comprehension]] is a generalization of the list comprehension to other [[monads in functional programming]].
| |
| | |
| ===Set comprehension===
| |
| Version 3.x and 2.7 of the Python language introduces syntax for [[set (computer science)|set]] comprehensions. Similar in form to list comprehensions, set comprehensions generate Python sets instead of lists.
| |
| <source lang="python">
| |
| >>> s = {v for v in 'ABCDABCD' if v not in 'CB'}
| |
| >>> print(s)
| |
| {'A', 'D'}
| |
| >>> type(s)
| |
| <class 'set'>
| |
| >>>
| |
| </source>
| |
| | |
| Racket set comprehensions generate Racket sets instead of lists.
| |
| <source lang="scheme">
| |
| (for/set ([v "ABCDABCD"] #:unless (member v (string->list "CB")))
| |
| v))
| |
| </source>
| |
| | |
| ===Dictionary comprehension===
| |
| Version 3.x and 2.7 of the Python language introduced a new syntax for [[associative array|dictionary]] comprehensions, similar in form to list comprehensions but which generate Python [http://docs.python.org/library/stdtypes.html#dict dicts] instead of lists.
| |
| <source lang="python">
| |
| >>> s = {key: val for key, val in enumerate('ABCD') if val not in 'CB'}
| |
| >>> s
| |
| {0: 'A', 3: 'D'}
| |
| >>>
| |
| </source>
| |
| | |
| Racket hash table comprehensions generate Racket hash tables (one implementation of the Racket dictionary type).
| |
| <source lang="scheme">
| |
| (for/hash ([(val key) (in-indexed "ABCD")]
| |
| #:unless (member val (string->list "CB")))
| |
| (values key val))
| |
| </source>
| |
| | |
| ===Parallel list comprehension===
| |
| 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 [[Map (higher-order function)|zipped]]).
| |
| <source lang="haskell">
| |
| -- regular list comprehension
| |
| a = [(x,y) | x <- [1..5], y <- [3..5]]
| |
| -- [(1,3),(1,4),(1,5),(2,3),(2,4) ...
| |
| | |
| -- zipped list comprehension
| |
| b = [(x,y) | (x,y) <- zip [1..5] [3..5]]
| |
| -- [(1,3),(2,4),(3,5)]
| |
| | |
| -- parallel list comprehension
| |
| c = [(x,y) | x <- [1..5] | y <- [3..5]]
| |
| -- [(1,3),(2,4),(3,5)]
| |
| </source>
| |
| | |
| 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.
| |
| <source lang="scheme">
| |
| > (for*/list ([x (in-range 1 6)] [y (in-range 3 6)]) (list 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))
| |
| > (for/list ([x (in-range 1 6)] [y (in-range 3 6)]) (list x y))
| |
| '((1 3) (2 4) (3 5))
| |
| </source>
| |
| | |
| In Python we could do as follows:
| |
| <source lang="python">
| |
| # regular list comprehension
| |
| >>> a = [(x, y) for x in range(1, 6) for y in range(3, 6)]
| |
| [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), ...
| |
| | |
| # parallel/zipped list comprehension
| |
| >>> b = [x for x in zip(range(1, 6), range(3, 6))]
| |
| [(1, 3), (2, 4), (3, 5)]
| |
| </source>
| |
| | |
| === XQuery and XPath ===
| |
| 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:
| |
| | |
| /library/book//paragraph[@style='first-in-chapter']
| |
| | |
| is conceptually evaluated as a series of "steps" where each step produces a list and the next step applies a filter function to each element in the previous step's output.<ref>{{cite web | url = http://www.w3.org/TR/xpath#section-Location-Steps | title = 2.1 Location Steps | work = XML Path Language (XPath) | date = 16 November 1999 | publisher = [[W3C]]}}</ref>
| |
| | |
| In XQuery, full XPath is available, but [[FLWOR]] statements are also used, which is a more powerful comprehension construct.<ref>{{cite web | url = http://www.w3schools.com/XQuery/xquery_flwor.asp | title = XQuery FLWOR Expressions | work = [[W3Schools]]}}</ref>
| |
| <source lang="sql">
| |
| for $b in //book
| |
| where $b[@pages < 400]
| |
| order by $b//title
| |
| return
| |
| <shortBook>
| |
| <title>{$b//title}</title>
| |
| <firstPara>{($book//paragraph)[1]}</firstPara>
| |
| </shortBook>
| |
| </source>
| |
| Here the XPath //book is evaluated to create a sequence (aka list); the where clause is a functional "filter", the order by sorts the result, and the <shortBook>...</shortBook> XML snippet is actually an anonymous function that builds/transforms XML for each element in the sequence using the 'map' approach found in other functional languages.
| |
| | |
| So, in another functional language the above FLWOR statement may be implemented like this:
| |
| | |
| map(
| |
| newXML(shortBook, newXML(title, $1.title), newXML(firstPara, $1...))
| |
| filter(
| |
| lt($1.pages, 400),
| |
| xpath(//book)
| |
| )
| |
| )
| |
| | |
| === LINQ in C# ===
| |
| | |
| [[C Sharp (programming language)|C#]] 3.0 has a group of related features called [[LINQ]], which defines a set of query operators for manipulating object enumerations.
| |
| | |
| <source lang="csharp">
| |
| var s = Enumerable.Range(0, 100).Where(x => x*x > 3).Select(x => x*2);
| |
| </source>
| |
| | |
| It also offers an alternative comprehension syntax, reminiscent of SQL:
| |
| | |
| <source lang="csharp">
| |
| var s = from x in Enumerable.Range(0, 100) where x*x > 3 select x*2;
| |
| </source>
| |
| | |
| 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
| |
| - rewrite an incompatible or inefficient comprehension
| |
| - translate the AST into another query language (e.g. SQL) for execution
| |
| | |
| === C++ ===
| |
| C++ does not have any language features directly supporting list comprehensions. 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.
| |
| <source lang="cpp">
| |
| #include <algorithm>
| |
| #include <list>
| |
| | |
| using namespace std;
| |
| | |
| template<class C, class P, class T>
| |
| C&& comprehend(C&& source, const P& predicate, const T& transformation)
| |
| {
| |
| // initialize destination
| |
| C d = forward(source);
| |
| | |
| // filter elements
| |
| d.erase(remove_if(begin(d), end(d), predicate), end(d));
| |
| | |
| // apply transformation
| |
| for_each(begin(d), end(d), transformation);
| |
| | |
| return d;
| |
| }
| |
| | |
| int main()
| |
| {
| |
| list<int> range(10);
| |
| // range is a list of 10 elements, all zero
| |
| iota(begin(range), end(range), 1);
| |
| // range now contains 1,2,...,10
| |
| | |
| list<int> result = comprehend(
| |
| range,
| |
| [](int x){return x*x <= 3;},
| |
| [](int &x){x *= 2;});
| |
| // result now contains 4,6,...,20
| |
| }
| |
| </source>
| |
| There is some effort in providing C++ with list-comprehension constructs/syntax similar to the set builder notation.
| |
| * In [[Boost C++ Libraries|Boost]].Range [http://www.boost.org/libs/range] library there is a notion of adaptors [http://www.boost.org/libs/range/doc/html/range/reference/adaptors.html] that can be applied by to any range and do filtering, transformation etc. With this library, the original Haskell example would look like (using Boost.Lambda [http://www.boost.org/libs/lambda] for anonymous filtering and transforming functions):
| |
| <source lang="cpp">
| |
| counting_range(1,10) | filtered( _1*_1 > 3 ) | transformed(ret<int>( _1*2 ))
| |
| </source>
| |
| Full example is here: http://codepad.org/y4bpgLJu
| |
| | |
| * This<ref>{{cite web | url = http://mfoliveira.org/blog/2011/01/04/simple-list-comprehension-in-cp-using-preprocessor-macros/ | title = Single-variable List Comprehension in C++ using Preprocessor Macros}}</ref> implementation uses a macro and overloads the << operator. It evaluates any expression valid inside an 'if', and any variable name may be chosen. It's not [[threadsafe]], however. Usage example:
| |
| <source lang="cpp">
| |
| list<int> N;
| |
| list<double> S;
| |
| | |
| for (int i = 0; i < 10; i++)
| |
| N.push_back(i);
| |
| | |
| S << list_comprehension(3.1415 * x, x, N, x*x > 3)
| |
| </source>
| |
| | |
| * This<ref>{{cite web | url = http://www.tedunangst.com/listcc.html | title = C++ list comprehensions}}</ref> implementation provides head/tail slicing using classes and operator overloading, and the | operator for filtering lists (using functions). Usage example:
| |
| <source lang="cpp">
| |
| bool even(int x) { return x % 2 == 0; }
| |
| bool x2(int &x) { x *= 2; return true; }
| |
| | |
| list<int> l, t;
| |
| int x, y;
| |
| | |
| 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;
| |
| </source>
| |
| | |
| ==See also==
| |
| *The [[Select (SQL)|SELECT]] statement together with its FROM and WHERE clauses in [[SQL#Queries|SQL]]
| |
| *[[Programming language]]
| |
| *[[Mathematical notation]]
| |
| *[[Monads in functional programming]] for monads and monadic notation in general
| |
| *For other programming language constructs used to process sequences:
| |
| **[[Generator (computer science)]]
| |
| **[[Map (higher-order function)]]
| |
| *For other programming language constructs copied from the mathematical notation:
| |
| **[[Guard (computing)]]
| |
| **[[Pattern matching]]
| |
| **[[Operator (programming)]]
| |
| | |
| ==Notes and references==
| |
| {{reflist}}
| |
| *[http://ftp.sunet.se/foldoc/foldoc.cgi?list+comprehension List Comprehension] in The Free On-line Dictionary of Computing, Editor Denis Howe.
| |
| *{{cite conference | first = Phil | last = Trinder | url = http://portal.acm.org/citation.cfm?coll=GUIDE&dl=GUIDE&id=135271 | title = Comprehensions, a query notation for DBPLs | booktitle = Proceedings of the third international workshop on Database programming languages: bulk types & persistent data, Nafplion, Greece | pages = 55–68 | year = 1992}}
| |
| *{{cite conference | first = Philip | last = Wadler |url = http://citeseer.ist.psu.edu/wadler92comprehending.html | title = Comprehending Monads | booktitle = Proceedings of the 1990 ACM Conference on LISP and Functional Programming, Nice | year = 1990}}
| |
| *{{cite conference | first = Limsoon | last = Wong | url = http://portal.acm.org/citation.cfm?id=351241&dl=ACM&coll=portal | title = The Functional Guts of the Kleisli Query System | conference = International Conference on Functional Programming | booktitle = Proceedings of the fifth ACM SIGPLAN international conference on Functional programming | pages = 1–10 | year = 2000}}
| |
| | |
| ===Haskell===
| |
| *The Haskell 98 Report, chapter [http://haskell.org/onlinereport/exps.html#list-comprehensions 3.11 List Comprehensions].
| |
| *The Glorious Glasgow Haskell Compilation System User's Guide, chapter [http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#parallel-list-comprehensions 7.3.4 Parallel List Comprehensions].
| |
| *The Hugs 98 User's Guide, chapter [http://cvs.haskell.org/Hugs/pages/users_guide/hugs-ghc.html#ZIP-COMPREHENSION 5.1.2 Parallel list comprehensions (a.k.a. zip-comprehensions)].
| |
| | |
| ===OCaml===
| |
| * [http://batteries.forge.ocamlcore.org/ OCaml Batteries Included]
| |
| * [http://batteries.forge.ocamlcore.org/doc.preview:batteries-alpha3/html/extensions.html Language extensions introduced in OCaml Batteries Included]
| |
| | |
| ===Python===
| |
| * Python Reference Manual, chapter [http://www.python.org/doc/2.4.1/ref/lists.html 5.2.4 List displays].
| |
| * Python Enhancement Proposal [http://www.python.org/peps/pep-0202.html PEP 202: List Comprehensions].
| |
| * Python Reference Manual, chapter [http://www.python.org/doc/2.4.1/ref/genexpr.html 5.2.5 Generator expressions].
| |
| * Python Enhancement Proposal [http://python.org/peps/pep-0289.html PEP 289: Generator Expressions].
| |
| | |
| ===Common Lisp===
| |
| * [http://rali.iro.umontreal.ca/Publications/urls/LapalmeLispComp.pdf Implementation of a Lisp comprehension macro] by Guy Lapalme
| |
| | |
| ===Clojure===
| |
| * [http://clojure.org/api#for Clojure API documentation - ''for'' macro]
| |
| | |
| ===Axiom===
| |
| * [http://page.axiom-developer.org/zope/mathaction/Streams Axiom stream examples]
| |
| | |
| ==External links==
| |
| * SQL-like set operations with list comprehension one-liners in the [http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/159974 Python Cookbook]
| |
| * [http://lambda-the-ultimate.org/classic/message11326.html Discussion on list comprehensions in Scheme and related constructs]
| |
| * [http://langexplr.blogspot.com/2007/02/list-comprehensions-across-languages_18.html List Comprehensions across languages]
| |
| | |
| [[Category:Programming constructs]]
| |
| [[Category:Articles with example code]]
| |
| [[Category:Articles with example Haskell code]]
| |
| [[Category:Articles with example Python code]]
| |
| [[Category:Articles with example Racket code]]
| |