[pro] why :key arguments?

Tamas Papp tkpapp at gmail.com
Tue Jul 5 09:51:16 UTC 2011


On Mon, 04 Jul 2011 20:11:56 +0300, Nikodemus Siivola wrote:

> On 4 July 2011 19:42, Pascal J. Bourguignon
> <pjb at informatimago.com> wrote:
> 
>> I don't think so.
> 
> I disagree strongly, and I'm pretty sure CLHS agrees with me, since it
> goes to the trouble of specifying what happens with FUNCALL.
> 
> CLHS, DEFINE-COMPILER-MACRO: "The &whole argument is bound to the form
> argument that is passed to the compiler macro function. The remaining
> lambda-list parameters are specified as if this form contained the
> function name in the car and the actual arguments in the cdr, but if the
> car of the actual form is the symbol funcall, then the destructuring of
> the arguments is actually performed using its cddr instead."
> 
> (I'm not really interested in fencing re. compiler-macros here, just
> trying to keep the record only moderately crooked. This is a sidetrack
> of epic proportions already: the OP asked about :KEY, not
> compiler-macros.)

I am very happy to learn about these things.  Currently I am working
on the algorithms and my main concern is to ensure correctness; speed
is secondary at this point, but even though I am not optimizing, I
want to keep my code optimizable later on.

My problem with the key argument is that it complicates the interface.  I 
would like to use the same interface for sample statistics and random 
variables, eg currently in CL-NUM-UTILS and CL-RANDOM I have

(mean #(1d0 2d0 3d0)) ; => 2, a sample mean
(mean (r-normal 2 1)) ; => 2d0, mean of a univariate normal distribution

If I had a :KEY argument, I would have to check that it is EQ to
#'identity or not provided in methods for random variables.

APPLY is not a major concern for me at the moment, all of these
functions have a fixed number of arguments (usually one or two).  So
compiler macros still look attractive: I guess I could just write them
for the function I define (eg MAP1), with the understanding that if
the user wants speed, he should stick to mapping with this function.

I also thought of the following possibility using runtime dispatch: 

(defstruct (w/key (:constructor w/key (key object)))
  key object)

(defgeneric mean (object)
  (:method ((obj w/key))
    (mean-w/key (w/key-object obj) (w/key-key obj)))
  (:method ((obj sequence))
    (/ (reduce #'+ obj) (length obj))))

(defmethod mean-w/key ((obj sequence) key)
  (/ (reduce #'+ obj :key key) (length obj)))

(mean #(1 2 3))                ; => 2
(mean (w/key #'1+ #(1 2 3)))   ; => 3

Tamas





More information about the pro mailing list