Yes, and in fewer tokens:
(def entropy (x)
(- (sum [* (p _) (log:p _)] x)))
I like macros, but I wouldn't use them in this case. Summing is close enough to mapping that the form above is easy for any Lisp programmer to understand.
I'd also argue that code size is a more meaningful measure of readability than familiarity. There's nothing intrinsically right about sigma notation. Some people are just more used to it. But since whatever notation you put in a language will eventually become familiar to its users, you should factor out familiarity when making design decisions, or at most use it to break ties. The notation above is honestly more readable to me, because it's what I'm used to.
I'm honored you read my post and replied to it.
> I'd also argue that code size is a more meaningful measure of readability than familiarity ... but since whatever notation you put in a language will eventually become familiar to its users, you should factor out familiarity when making design decisions
An exaggerated, uncharitable interpretation of what you said would be "users will figure out the notation, regardless of how hard it is, so make them jump through hoops so you can get a shorter notation". How do you distinguish between shorter notation that is a net win, and shorter notation that looks like perl?
My goal in using the macro was to reduce noise. Without the macro, the equivalent clojure would look like
To me, the original version is easier to read because it lacks the #, % characters. Given that every call to sum would likely use an anonymous function (and therefore use #, %), it seemed worthwhile. Maybe that's an argument against clojure, but the arc version is almost as noisy, IMO.
If you can write something as a function, that's always a better option than making it a macro. It's clear to any clojure programmer what your entropy function does, just like it's clear to any Perl programmer what all that "line noise" is. (Arguably, there isn't much line noise in Perl, only in regular expressions, which every other language has stolen Perl's implementation of. If you want real line noise regexps, try Emacs Lisp without "rx".)
I totally agree. But his article was aimed at non-Clojure (probably non-Lisp) programmers.
Perhaps it's the function shorthand syntax that resembles Perl. This is closer to your macro's surface syntax:
The tradeoff with your macro version is that when you want to leverage Σ as a first-class function (say, with comp or partial), you will end up with #() or (fn..) in the calling code. You can't escape it -- it's a natural way to write functional Lisp code.
It's no less readable than the rest of Clojure's API. You can reasonably expect a Clojure user to understand functions as arguments.
I think we should distinguish between notations that allow users to write incomprehensibly terse code and those that force them to. Only the latter are a problem, unless you're taking the protect-users-from-themselves approach to language design.
It's an interesting question whether there are any existing language constructs that force one to write unreadable code. I ended
http://www.paulgraham.com/power.html
by asking for examples, and I don't think I ever got any.
"Are there languages that force you to write code in a way that is crabbed and incomprehensible?"
How about TECO?
> It's an interesting question whether there are any existing language constructs that force one to write unreadable code.
Depends. Suppose we added GoTo, ComeFrom, and assignment to the Haskell specification, to be implemented by all conforming implementations. The language has become strictly more powerful. But compiler writers will have a much harder time proving certain properties about your program e.g. constancy of variables. The implementation and optimisation techniques that depend on those properties no longer work. Thus the purely functional parts of your programmes will become slower, and you will be forced to switch to imperative style if you want any performance.
(To make the compiler writers job even more difficult, add some of Python's dynamic capabilities that make it so hard to compile. Plus an eval that works in the current environment on strings and can change arbitrary variables or cause other side-effects.)
Of course the language itself does not force you to write unreadable code. But it may make it harder for the implementors to allow you to write readable code.
While I see where you’re coming from as an application programming, people who do primarily scientific programming ∑ is much more intuitive than 'sum'. When I was doing scientific programming I would have killed for unicode source support. There isn’t always an obvious way to transform a math variable into ASCII. Consider,β for example, which can mean “the ratio of the thermal energy density to the magnetic energy density of a plasma”. In conversation people generally pronounce that as just “beta”. You could spell “beta” out in code, of course, but what if you have a β sub σ and a β sub s to juggle? And what if you have a prime or a superscript on those variables too?
The hairier equations can juggle several similar variables and carry on for several lines of code. It isn’t always obvious how to break them apart into smaller functions like you would in a normal application. Using income literals instead of spelling variables out can save a lot of space. More importantly, it makes the code look more like the source material, which makes mistakes much easier to spot.