Hacker News new | ask | show | jobs
by angusgr 5653 days ago
I think it's a double-edged sword.

I've both written and read code in non-functional languages where the "easy" way of doing it is thrown aside for the "cool functional" way of doing it. Leading to code which was more fun to write, looks cooler, but is also hard to read and written in a different idiom to the actual programming language. Bad.

I'm 100% guilty of this, although I try to stay vigilant. The other day I refactored out a gnarly bit of a Python API, but caught myself feeling sad because it meant deleting a bunch of clever lambda functions I was using to work around it in the first place. Bad!

That said, the other side of the double-edged sword is great - things that lead to giant tangled messes of procedural code can be turned into very nice functional-style constructs. Also, I love having list comprehensions in Python.

1 comments

Usually list comprehensions are a much cleaner way to write a map. This I love.

Personally what I love most about using more functional code aren't the clever lambda's and stuff, I actually try to avoid that because it looks weird in Python. What's really awesome is enclosing named functions inside bigger functions and using closures.

The result is code where:

1. nobody can, by accident or intentionally, use inner functions of your algorithm,

2. self-documented code (function name says what the code block does)

3. you aren't passing a gazillion parameters around

4. or making everything messy with a bunch of unneeded OOP code. [I don't like useless OOP code. Objects-just-for-the-sake-of-encapsulation are silly.]

edited for wall-of-text

> Usually list comprehensions are a much cleaner way to write a map.

But the first makes my intent clearer than the second:

    map(f, xs)

    [f(x) for x in xs]
In Python, where creating anonymous functions is syntactically expensive, list-comprehension syntax may be cheaper in many cases, but it's not clearer. When I want to map or filter something, I want to _say_ that I'm mapping or filtering, not explain to Python how to map or filter that thing in terms of list-comprehension syntax. Nor do I want to burden the reader with interpreting that syntax to figure out that it's a mapping or filtering operation.

I want my code to say what I mean, not just evaluate to what I mean.

>But the first makes my intent clearer than the second

That is entirely a matter of opinion. I would say python programmers with no functional background would find the list comprehension clearer, because that is the idiomatic python way.

May would have no idea what map even does without looking it up on the net.

> That is entirely a matter of opinion.

It isn't entirely a matter of opinion, is it? When you use map to do your mapping, aren't you are stating your intent in the language of the profession? The name of the function, after all, is "map," and isn't this term's meaning rather firmly established in mathematics and computer science? So, the idea of calling a map a map has some precedent that we can use to justify the practice, doesn't it?

Now, if your audience has no notion of what a mapping is, then, yes, there's a level of semantic intent that you're not going to be able to communicate to them. (At least until they learn the concept; it's common, worth learning, and not hard to grasp.) But that doesn't mean that you should refuse to call an important concept by its established name.

Concepts, after all, earn their names for a reason. If a concept has one, it's probably best to use it.

> I want my code to say what I mean, not just evaluate to what I mean.

This is an awesome rule of thumb. A more succinct version of Knuth's "Programs are meant to be read by humans and only incidentally for computers to execute"

> the first makes my intent clearer than the second:

I really think the beauty of list comprehensions may be in the eye of the beholder.

I personally find the list comprehension syntax easier to read than equivalent map syntax most of the time, especially (as you point out) for cases where you want an anonymous function (ie quite often), but even for simple ones like your example.

Doubly so when you start chaining map & filter functionality to do one thing. Statements like [ f(x) for x in xs if g(x) > 3 ] seem to read quite nicely for me. You only need to change two words and you have a pseudocode description: "f(x) for all x in xs where g(x) > 3".

This is obviously subjective, though, and maybe I'm in the minority. I knew list comprehensions before I knew Python, so I'll accept that makes me suspect.

(Edited for clarity)

That depends. When you're doing simple translations the list way is much cleaner.

   ids = [item.id for item in all_items]
Seems much cleaner than

   ids = map(lambda item: item.id, all_items)
But yes, I agree, when you have to actually perform some less-than-trivial computation on every item of a list, map is much cleaner.
But the first of your examples is cleaner not because of any inherent advantage of list-comprehension syntax but because in Python the syntactic cost of turning an expression into an anonymous function is so high. In other words, you're comparing (cognitive cost of comprehension + low cost of expression) against (cognitive cost of map + high cost of promoting an expression to an anonymous function).

Don't blame map for Python's tax on expression-promotion. ;-)