Tamas Papp tkpapp@gmail.com writes:
On Mon, 04 Jul 2011 14:20:32 +0400, Stas Boukarev wrote:
Tamas Papp tkpapp@gmail.com writes:
On Mon, 04 Jul 2011 11:39:39 +0200, Hans Hübner wrote:
On Mon, Jul 4, 2011 at 11:31 AM, Tamas Papp tkpapp@gmail.com wrote:
Why do some CL library functions have :key arguments?
[...]
but it is a bit cumbersome. I can make my code simpler by relying on calls like
(quantiles (map 'vector key vector) quantiles)
This not only conses "a bit more", it also duplicates traversal efforts - The original list must be traversed, and the consed-up list of key values as well. I think it is prudent that the CL library functions offer ways to reduce consing for cases where "a bit" is too much (and "a bit" can become a lot if a program operates on long lists).
I understand this. My main question is: why not do this with compiler macros? Is there any reason for this, other than historical?
Because it's not easy to do with compiler macros.
Can you (or someone) please elaborate on that? I have just started reading up on compiler macros, and I don't understand why.
Suppose you have a function SUM,
(defun sum (list) (loop for i in list sum i))
Now if you want to optimize (sum (map 'list KEY list)), you would need to write an additional function.
(defun sum-key (list key) (loop for i in list sum (funcall key i)))
And then you would need to write a compiler macro, which would match (map 'list KEY sequence) and transform it into (sum-key sequence KEY), which is not that hard, if that's only what you have. Now what if you want it to work with (mapcar KEY list) too. It becomes more and more cumbersome as it gets more general.
And now you need two functions, a clever compiler macro (perhaps using some pattern matching library), and which may not do what the user expects.
While you could have all that with just one function:
(defun sum (list &key key) (loop for i in list sum (if key (funcall key i) i))) Other disadvantages of compiler-macros:
* They are not guaranteed to be expanded. Some implementations may ignore them. * They can't be used with APPLY or FUNCALL. * You can't compose them e.g. if you wanted to write (defun two-sum (list1 list2) (+ (sum list1) (sum list2))) You would need to write a second compiler macro. While with KEY keyword you could just pass it along.