What is a solid example of something that can be done with list comprehensions that is tricky with high order functions? What is a solid example of something that can be done with list comprehensions that is tricky with high order functions? python python

What is a solid example of something that can be done with list comprehensions that is tricky with high order functions?


The answer is that there is no such example. Everything you can do with list comprehensions has a mechanical translation to higher-order functions. In fact, this is how Haskell implements list comprehensions: it desugars them to higher-order functions.

Given a list comprehension like this:

[(x, y) | x <- [1..3], y <- [4..6]]

Haskell desugars it to:

concatMap (\x -> concatMap (\y -> [(x, y)]) [4..6]) [1..3]

Similarly, if you put in predicates like:

[(x, y) | x <- [1..3], y <- [4..6], x + y /= 5]

... then that desugars to:

concatMap (\x -> concatMap (\y -> if (x + y) == 5 then [(x, y)] else []) [4..6]) [1..3]

In fact, this desugaring is part of the Haskell specification, which you can find here.


As has been said, everything you can do with list comprehensions can be desugared into higher-order functions, but a large part of the problem with doing this in Python is that Python lacks support for the kind of point-free programming you can use with filter, map, and friends in Haskell. Here's a somewhat contrived example, but I think you'll get the idea.

Let's take this Python code:

[(x,y) for x,y in zip(xrange(20), xrange(20, 0, -1)) if x % 2 == 0 and y % 2 == 0]

All it does is print this out:

[(0, 20), (2, 18), (4, 16), (6, 14), (8, 12), (10, 10), (12, 8), (14, 6), (16, 4), (18, 2)]

Here's the equivalent version with filter:

filter(lambda ns : ns[0] % 2 == 0 and ns[1] % 2 == 0, zip(xrange(20), xrange(20, 0, -1)))

I hope you'll agree with me that it's a lot uglier. There isn't really much you can do to make it less ugly without defining a separate function.

But let's look at the equivalent version in Haskell:

[(x,y) | (x,y) <- zip [0..20] [20,19..0], x `mod` 2 == 0 && y `mod` 2 == 0]

Okay, pretty much as good as the Python list comprehension version. What about the equivalent filter version?

import Data.Functionlet f = (&&) `on` (==0) . (`mod` 2)filter (uncurry f) $ zip [0..20] [20,19..0]

Okay, we had to do an import, but the code is (imo) a lot clearer once you understand what it does, although some people might still prefer f to be pointed, or even a lambda with filter. In my opinion the point-free version is more concise and conceptually clear. But the main point I want to make is that it is not really going to be this clear in Python because of the inability to partially apply functions without bringing in a separate library, and the lack of a composition operator, so in Python it is a good idea to prefer list comprehensions over map/filter, but in Haskell it can go either way depending on the specific problem.


In Haskell, list comprehensions are 'syntactic sugar' for conditionals and functions (or can trivially be translated into do notation and then desugared monadically). Here's the 'official' guide to translating them: http://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-420003.11

Hence, since list comprehensions can be translated mechanically and straightforwardly into equivalent code using simply higher order functions, there is by definition nothing you can do with them that is difficult to do without them.