Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

I've heard from many Pythonists that they prefer list comprehensions because they can do everything you can do using high order functions such as filter and reduce, and more. So this question address them: what is a solid example of something you can do with them, that is tricky to do with HOFs?

like image 688
MaiaVictor Avatar asked May 28 '13 04:05

MaiaVictor


People also ask

What do list comprehensions do give suitable example?

List comprehension offers a shorter syntax when you want to create a new list based on the values of an existing list. Example: Based on a list of fruits, you want a new list, containing only the fruits with the letter "a" in the name.

What are list comprehensions used for?

List comprehension is an elegant way to define and create lists based on existing lists. List comprehension is generally more compact and faster than normal functions and loops for creating list. However, we should avoid writing very long list comprehensions in one line to ensure that code is user-friendly.

Are list comprehensions functional?

One of the language's most distinctive features is the list comprehension, which you can use to create powerful functionality within a single line of code.

Are list comprehensions more efficient?

Conclusions. List comprehensions are often not only more readable but also faster than using “for loops.” They can simplify your code, but if you put too much logic inside, they will instead become harder to read and understand.


2 Answers

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.

like image 70
Gabriella Gonzalez Avatar answered Oct 07 '22 21:10

Gabriella Gonzalez


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.Function
let 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.

like image 43
Wes Avatar answered Oct 07 '22 21:10

Wes