This is the monad template, in particular the list monad. In many languages, monads are hidden behind some kind of syntactic sugar, for example C # LINQ , Scala concept sequences , Haskell do-notation, or, in more languages, (multi-) (for example, in Python).
The key term in translating from any of these sugar syntaxes to ordinary functions is (in the particular case of lists) a function of the type ([a], a -> [b]) -> [b] , which is an essential part of the definition of a monad. This function is known by various names, for example. (>>=) or "bind", flatMap or concatMap , or selectMany .
In the case of lists, concatMap or flatMap is probably the best name because this is what it does: map the function that returns the lists above the list by specifying a list of lists; then flatten this list.
Now for something more specific 1 :
> from functools import reduce > from operator import add > def concatMap(xs, f): return reduce(add, map(f, xs), []) # only map and reduce!
Testing:
> [x*y for x in range(1 ,5) for y in range(x, 5)] > [1, 2, 3, 4, 4, 6, 8, 9, 12, 16] > concatMap(range(1, 5), lambda x: concatMap(range(x, 5), lambda y:[x*y])) > [1, 2, 3, 4, 4, 6, 8, 9, 12, 16]
And more fun:
> [x*y+z for x in range(1, 5) for y in range(x, 5) for z in range(x, y)] > [3, 4, 5, 5, 6, 7, 8, 10, 11, 15] > concatMap(range(1, 5),lambda x: concatMap(range(x, 5), lambda y: concatMap(range(x, y),lambda z: [x*y+z]))) > [3, 4, 5, 5, 6, 7, 8, 10, 11, 15]
Finally, it should be noted that although the map like function is always required for the monad, as a rule, reduce not enough, but in fact, we need a generalized join “smoothing” operation with a type of type m<m<a>> (using the template / generalization syntax ), where m is the type of monad under consideration.
1 As noted in the comments, this can also be defined as concatMap = lambda xs, f: chain.from_iterable(map(f, xs)) using itertools and the identity (>>=) ≡ join . fmap (>>=) ≡ join . fmap .