UPDATE: fixed an erroneous example.
Finally pulled my finger out and started releasing. First to face the mess that is the real world is cl-op, my attempt at partial application in Common Lisp.
I harbor no illusions this is something novel but as far as I can tell there is no canonical way of doing it. There is curly but I am not a big fan of reader macros. A lot of projects seem to roll their own but it sucks to depend on a massive code-base for such a small and simple utility. Besides such approaches are often tailored to a specific need and introduce additional impedance if used outside their scope.
Enough rationalisation, let’s get down to business:
(mapcar (op / (+ _ _)) '(2 3 4) '(2 3 4)) => '(1/4 1/6 1/8)
Careful readers will note / is passed as a function name not a designator. When cleaning up cl-op for release I initially changed this to accept function designators like funcall but latter decided against it. Why? Two reasons:
1) it makes Lisp-2 less of a compromise. I’m a lazy and hate function-quoting.
2) plays nice with macros.
The biggest cons was inconsistency but then I remember function works exactly the same way. I fact, I dare say op is semantically closer to function (the creates a lexical closure bit to be precise) than funcall.
An important consideration when writing cl-op was performance. That is why op lifts all complex arguments not containing slots to a closure. In code-speak:
(op foo (baz 1 2 3) (bar _)) == (let ((#:G100 (baz 1 2 3))) (lambda (#:G101) (foo #:G100 (bar #:G101))))
For cases where such behavior is not desired (i.e. relying on side-effects), there is op* which works exactly like op except for invariant lifting:
(mapcar (op + _ (random 100)) '(1 1 1 1 1)) => '(26 26 26 26 26) (mapcar (op* + _ (random 100)) '(1 1 1 1 1)) => '(51 51 89 13 99)
In addition partial application equivalents (with and without invariant lifting) of funcall, apply and multiple-value-call are provided.
pfuncall is here primarily to compensate for op’s inability to handle functions passed by value. However it also opens an interesting possibility of having function argument as a slot:
(mapcar (pfuncall _ '(1 2 3 4 5))
(list #'first (op nth 2 _))) => '(1 3)
The rest should be pretty self-explanatory, besides there is even a semblance of documentation at the official homepage.
![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_e.png?x-id=b5b34a46-adc1-4556-a77e-a98a39a42861)






