List comprehensions: Difference between revisions

→‎{{header|Python}}: Three equivalent formulations of list comprehension as a use of the list monad
(Added Factor)
(→‎{{header|Python}}: Three equivalent formulations of list comprehension as a use of the list monad)
Line 1,823:
 
<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}}==
9,655

edits