List comprehensions: Difference between revisions
Content added Content deleted
(Added Factor) |
(→{{header|Python}}: Three equivalent formulations of list comprehension as a use of the list monad) |
||
Line 1,823: | Line 1,823: | ||
<lang python>((x, y, z) for (x, y, z) in triplets(n) if x**2 + y**2 == z**2)</lang> |
<lang python>((x, y, z) for (x, y, z) in triplets(n) if x**2 + y**2 == z**2)</lang> |
||
More generally, the list comprehension syntax can be understood as a concise syntactic sugaring of a use of the list monad, in which non-matches are returned as empty lists, matches are wrapped as single-item lists, and concatenation flattens the output, eliminating the empty lists. |
|||
The monadic 'bind' operator for lists is concatMap, traditionally used with its first two arguments flipped. The following three formulations of a **pt** (pythagorean triangles) function are equivalent: |
|||
<lang python>from functools import (reduce) |
|||
from operator import (add) |
|||
# pts :: Int -> [(Int, Int, Int)] |
|||
def pts(n): |
|||
m = 1 + n |
|||
return [(x, y, z) for x in xrange(1, m) |
|||
for y in xrange(x, m) |
|||
for z in xrange(y, m) if x**2 + y**2 == z**2] |
|||
# pts2 :: Int -> [(Int, Int, Int)] |
|||
def pts2(n): |
|||
m = 1 + n |
|||
return bindList( |
|||
xrange(1, m) |
|||
)(lambda x: bindList( |
|||
xrange(x, m) |
|||
)(lambda y: bindList( |
|||
xrange(y, m) |
|||
)(lambda z: [(x, y, z)] if x**2 + y**2 == z**2 else []))) |
|||
# pts3 :: Int -> [(Int, Int, Int)] |
|||
def pts3(n): |
|||
m = 1 + n |
|||
return concatMap( |
|||
lambda x: concatMap( |
|||
lambda y: concatMap( |
|||
lambda z: [(x, y, z)] if x**2 + y**2 == z**2 else [] |
|||
)(xrange(y, m)) |
|||
)(xrange(x, m)) |
|||
)(xrange(1, m)) |
|||
# GENERIC --------------------------------------------------------- |
|||
# concatMap :: (a -> [b]) -> [a] -> [b] |
|||
def concatMap(f): |
|||
return lambda xs: ( |
|||
reduce(add, map(f, xs), []) |
|||
) |
|||
# (flip concatMap) |
|||
# bindList :: [a] -> (a -> [b]) -> [b] |
|||
def bindList(xs): |
|||
return lambda f: ( |
|||
reduce(add, map(f, xs), []) |
|||
) |
|||
def main(): |
|||
for f in [pts, pts2, pts3]: |
|||
print (f(20)) |
|||
main()</lang> |
|||
{{Out}} |
|||
<pre>[(3, 4, 5), (5, 12, 13), (6, 8, 10), (8, 15, 17), (9, 12, 15), (12, 16, 20)] |
|||
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (8, 15, 17), (9, 12, 15), (12, 16, 20)] |
|||
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (8, 15, 17), (9, 12, 15), (12, 16, 20)]</pre> |
|||
=={{header|R}}== |
=={{header|R}}== |