I think the point was that author was able to create a syntax for summation that had approximately the same shape as the math notation.
I don't think I would argue that this is a very good example of macros (and yes, I wrote that before reading pg's comment ;), but solutions people have posted with other languages all have foreign symbols in them -- syntax for passing around blocks, or language-defined looping or list comprehension syntax, not ones they have chosen to suit their own needs. In this case, that's a virtue; you learn the language's syntax, and then you know how to recognize summation within any program in that language regardless of who wrote it, but in cases where the problem is more complicated and the native syntax for what you need to do more awkward, you really do want to create your own syntax.
Arguably that's a danger inherent in Lisp: it gives more opportunities to create needless new syntax, not just the kind of syntax that makes a program clearer and simpler.
If you wanted to extend destructuring in Python (that is, (a, b) = (1, 2)) to cover dictionaries, how would you do it? In a Lisp, it's done with macros. The core language usually doesn't start out with any destructuring at all. In Python, you can beg Guido and wait, or fork the project -- neither option is practical.
Sorry, I should have given an example. I don't see how the above is ever likely to be useful, since the keys can be in any arbitrary order, but the fact that you can get something sequential out of a dictionary and revert back to tuple assignment is trivial.
What I'd like to see you do in Python is this:
>>> d = { 'key1': 'val1', 'key2': 'val2', 'key3': 'val3' }
>>> { 'key1': x, 'key3': y } = d
>>> (x,y)
('val1', 'val3')
Nothing like this is built into the handful of special forms that Clojure starts out with, but roughly halfway through core.clj, it gets added to the language using the same macro facilities available to any Clojure programmer. If Python manages to be as powerful a language as Clojure without macros, you should have no trouble at all.
but the fact that you can get something sequential out of a dictionary and revert back to tuple assignment is trivial.
I disagree with this assertion. This functionality is not trivial and it wasn't in early Python versions -- certainly not before the introduction of __iter__!
It's existence is testimony to the continuing evolution, and consistency of the Python language. Whether this is a good thing or not I suppose depends on your point of view. I imagine Lispers would see it as a black mark that we had to wait for Guido to implement it. Pythonistas on the other hand probably value the fact that it was well thought out and discussed via a PEP, and is universally implemented. Perhaps both are valid points of view.
Your challenge is interesting because it's so easy to solve in Python that I can't imagine anyone except a Lisp programmer seeing anything in it to object to. In Python it is trivial to replicate the functionality albeit with a different syntax -- and syntax seems to be king for many Lisp fans.
I like the Python version because I have to understand only two concepts to work out what's happening: Firstly there's a function call. Secondly the iterable result of the call is unpacked to a tuple.
The merits of the Clojure version I'm not qualified to say, but is it really better in all regards than the Python equivalent? Even clarity, readability, comprehensibility?
First of all, I certainly wasn't claiming that you couldn't look up more than one hash key on one line of code, using a function. My point is that you might reasonably want to extend the concept of destructuring further to cover dictionaries, and that macros allow you to extend the language in that way.
Clarity, readability, and comprehensibility are three words that, in programming, mean pretty much the same thing as familiarity. To me, if I weren't looking at the definition of unpack, the above would look weird because I'd think of the Perl function unpack(), which does something very different. unpack(d, keys) above isn't something you'd even write in Clojure because it would be a synonym for (map d keys). Aside from that, it does seem very straightforward, if limited. Clojure does win on generality, because the Clojure version nests, covering sequential data structures at the same time:
Yes. Why should something which is NOT written in prefix notation in math be written in prefix notation in code? What is so impressive about that? All of my programming languages (who has just one?) can define nice looking functions. None of them use obscure prefix notation, and I think that's a good thing.
What's so obscure about prefix notation? Having to deal with state and order of computation is a much bigger headache when converting from math to code than fixity.
For all the talk of how Lisp is so well suited to making minilanguages for expressing things own their own terms, the lack of infix arithmetic seems particularly jarring.
I think that infix (Lisps), postfix (Forth), or all-left OR all-right associative (as in Smalltalk and J, respectively) are better choices than infix with order-of-operations (which is just historical cruft, IMHO), but making basic arithmetic awkward is an easy way to give people a bad first impression of a language. In OCaml, which has order-of-operations arithmetic syntax, people instead get mad because it uses different ops (*. +. etc) for floating point math. You can't win.
Haskell has solved these problems quite nicely for me. You can use infix or prefix. And you can make any operator prefix by enclosing it in parens. The other way round, you have to backtick your function to make it infix. And it uses typeclasses to (mostly) allow the same operators for all numeric types.
There's a way to set the infix associativity and precedence, isn't there? (I'm rusty at Haskell, it's not my thing.)
You can do typeclass-like overloading in OCaml via its module system, but it isn't really integrated into basic arithmetic, which probably would have been the single most useful place for it. (I just got used to it, but it's definitely a wart.)
In idiomatic Python, with only basic language features needed:
-sum(p(x) * log(p(x)) for x in l)