Difference between revisions of "List comprehension"
(Fleshed out stub for list comprehensions) 
(comparison with List monad) 

Line 5:  Line 5:  
[toUpper c  c < s] 
[toUpper c  c < s] 

</haskell> 
</haskell> 

⚫  
+  where <hask>s :: String</hask> is a string such as <hask>"Hello"</hask>. 

⚫  
+  The result of this list comprehension is <hask>"HELLO"</hask>. 

+  (Of course, in this simple example you would just write <hask>map toUpper s</hask>.) 

+  
+  == Examples == 

One may have multiple generators, separated by commas, such as 
One may have multiple generators, separated by commas, such as 

Line 61:  Line 66:  
The specification of list comprehensions is given in [http://haskell.org/onlinereport/exps.html#sect3.11 The Haskell 98 Report: 3.11 List Comprehensions]. 
The specification of list comprehensions is given in [http://haskell.org/onlinereport/exps.html#sect3.11 The Haskell 98 Report: 3.11 List Comprehensions]. 

−  +  The GHC compiler supports parallel list comprehensions as an extension; see [http://www.haskell.org/ghc/docs/latest/html/users_guide/syntaxextns.html#parallellistcomprehensions GHC User's Guide: 7.3.4. Parallel List Comprehensions]. 

+  
+  == List monad == 

+  
+  In the first versions, the comprehension syntax was available for all [[monad]]s. (See [[History of Haskell]]) 

+  Later the comprehension syntax was restricted to lists. 

+  Since lists are an instance of monads, you can get list comprehension in terms of the <hask>do</hask> notation. 

+  Because of this, several Haskell programmers consider the list comprehension unnecessary now. 

+  
+  The examples from above can be translated to list monad as follows: 

+  <haskell> 

+  do c < s 

+  return (toUpper c) 

+  </haskell> 

+  
+  <haskell> 

+  do i < [1,2] 

+  j < [1..4] 

+  return (i,j) 

+  </haskell> 

+  or 

+  <haskell> 

+  liftM2 (,) [1,2] [1..4] 

+  </haskell> 

+  
+  <haskell> 

+  do j < [1..] 

+  return 

+  (do i < [1,2] 

+  return (i,j)) 

+  </haskell> 

+  
+  <haskell> 

+  do i < [1..] 

+  j < [1..i1] 

+  guard (gcd i j == 1) 

+  return (i,j) 

+  </haskell> 

+  
+  <haskell> 

+  do i < [1..] 

+  let k = i*i 

+  j < [1..k] 

+  return (i,j) 

+  </haskell> 

+  
+  [http://en.wikipedia.org/wiki/Sieve_of_Atkin Sieve of Atkin]: 

+  <haskell> 

+  do m < [1..60] 

+  n < [1..60] 

+  guard (mod (poly m n) 60 == k) 

+  return $ 

+  do j < [0..] 

+  let y = n + 60*j 

+  return $ 

+  do i < [0..] 

+  let x = m + 60*i 

+  guard (test x y) 

+  return (poly x y) 

+  </haskell> 

+  
[[Category:Glossary]] 
[[Category:Glossary]] 
Revision as of 13:23, 3 September 2007
List comprehensions are syntactic sugar like the expression
import Data.Char (toUpper)
[toUpper c  c < s]
where s :: String
is a string such as "Hello"
.
Strings in Haskell are lists of characters; the generator c < s
feeds each character of s
in turn to the lefthand expression toUpper c
, building a new list.
The result of this list comprehension is "HELLO"
.
(Of course, in this simple example you would just write map toUpper s
.)
Examples
One may have multiple generators, separated by commas, such as
[(i,j)  i < [1,2], j < [1..4]]
yielding the result
[(1,1),(1,2),(1,3),(1,4),(2,1),(2,2),(2,3),(2,4)]
Note how each successive generator refines the results of the previous generator. Thus, if the second list is infinite, one will never reach the second element of the first list. For example,
take 10 [ (i,j)  i < [1,2], j < [1..]]
yields
[(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10)]
In such a situation, a nested sequence of list comprehensions may be appropriate. For example,
take 5 [[ (i,j)  i < [1,2]]  j < [1..]]
yields
[[(1,1),(2,1)], [(1,2),(2,2)], [(1,3),(2,3)], [(1,4),(2,4)], [(1,5),(2,5)]]
One can also provide boolean guards. For example,
take 10 [ (i,j)  i < [1..], j < [1..i1], gcd i j == 1 ]
yields
[(2,1),(3,1),(3,2),(4,1),(4,3),(5,1),(5,2),(5,3),(5,4),(6,1)]
Finally, one can also make local let declarations. For example,
take 10 [ (i,j)  i < [1..], let k = i*i, j < [1..k]]
yields
[(1,1),(2,1),(2,2),(2,3),(2,4),(3,1),(3,2),(3,3),(3,4),(3,5)]
Here is an example of a nested sequence of list comprehensions, taken from code implementing the Sieve of Atkin:
[[[ poly x y
 i < [0..], let x = m + 60*i, test x y ]
 j < [0..], let y = n + 60*j ]
 m < [1..60], n < [1..60], mod (poly m n) 60 == k ]
The result is a list of infinite lists of infinite lists.
The specification of list comprehensions is given in The Haskell 98 Report: 3.11 List Comprehensions.
The GHC compiler supports parallel list comprehensions as an extension; see GHC User's Guide: 7.3.4. Parallel List Comprehensions.
List monad
In the first versions, the comprehension syntax was available for all monads. (See History of Haskell)
Later the comprehension syntax was restricted to lists.
Since lists are an instance of monads, you can get list comprehension in terms of the do
notation.
Because of this, several Haskell programmers consider the list comprehension unnecessary now.
The examples from above can be translated to list monad as follows:
do c < s
return (toUpper c)
do i < [1,2]
j < [1..4]
return (i,j)
or
liftM2 (,) [1,2] [1..4]
do j < [1..]
return
(do i < [1,2]
return (i,j))
do i < [1..]
j < [1..i1]
guard (gcd i j == 1)
return (i,j)
do i < [1..]
let k = i*i
j < [1..k]
return (i,j)
do m < [1..60]
n < [1..60]
guard (mod (poly m n) 60 == k)
return $
do j < [0..]
let y = n + 60*j
return $
do i < [0..]
let x = m + 60*i
guard (test x y)
return (poly x y)