The -> macro.
(-> {}
(add-person 'servbot)
add-age
add-info
add-to-db
notify-status-by-email
log-user-addition
)
So the threading operator is exactly what you ask. It inserts the results of the previous expression as the first argument as the first argument as the next expression. Note this still supports situations where an expression can take more than one argument.Additionally, there is the ->> operator which inserts the previous result as the last argument in the next expression and some a library that includes the "magic wand" operator "-<>" ala
(-<> {}
(add-person 'servbot)
(add-age 21 <>)
(add-info 'servbot <> 21)
(add-to-db 'my-db-handle 5432 <>)
notify-status-by-email
(log-user-addition 'dev 'email <> 'paint-by-numbers)
)
This particular set of macros seems entirely trivial until you use it, and then it changes your entire perspective of what functions do since your ability to express the computation pipeline changes completely.Edit: Update for formatting.
(as-> {} <>
...
(add-age 21 <>)
...)That being said, I write Java for a living, and I don't find it terribly verbose, outside of the lack of sum types, pattern matching, and typeclasses.
So basically being able to run an arbitrary number of dependent, nested loops. Now imagine you want to run arbitrary code in the interior, rather than just incrementing a count.
It's a simple idea. And it can be expressed so succinctly in just a few lines of pseudocode in a freshman-level computer science textbook.
And yet I wouldn't want to touch this in Java. The lisp macro to write this isn't much more verbose than the pseudocode itself.
[0] Rosen's Discrete Mathematics and Its Applications, 7th e.
Edit: Traded formatting for pastebin
However, there's a reason Java is in the top 3 most popular languages. Its pragmatic, it scales, it plays nice with tooling and the language itself is pretty passable.
I wonder if those are true reasons. I currently believe in the following set of reasons, in the order of importance: runaway feedback loop of popularity (popularity -> jobs -> popularity), JVM is cross-platform, low cognitive effort per line of code written.
I'm currently dabbling in Android development, and the few Java libraries I've dealt with, especially Android's own APIs, have been a thorough exercise in frustration, to put it mildly.
Where are the good Java codebases hiding?
The article could be improved by including an example. Pick one in which Java makes the problem to be solved tedious, verbose, repetitive, or error-prone and where Lisp macros do not. Bias the example as much as possible to a problem where Lisp can shine. It should, however, be a real problem most programmers are likely to face in some form.
Then present the source for both solutions.
This approach would even help those who don't use Java regularly because they could try to implement the same functionality in their language of choice and compare it the the Lisp implementation.