Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the definition for `apply-partially` work in Emacs 24?

The Emacs code for apply-partially is this:

(defun apply-partially (fun &rest args)
  "Return a function that is a partial application of FUN to ARGS.
ARGS is a list of the first N arguments to pass to FUN.
The result is a new function which does the same as FUN, except that
the first N arguments are fixed at the values with which this function
was called."
  `(closure (t) (&rest args)
            (apply ',fun ,@(mapcar (lambda (arg) `',arg) args) args)))

It returns a list that looks a lot like a lambda expression, except that lambda is replaced by closure (t). For example, (apply-partially 'cons 1) returns this:

(closure (t) (&rest args) (apply (quote cons) (quote 1) args))

which, as far as I can tell, looks and works exactly like this:

(lambda (&rest args) (apply (quote cons) (quote 1) args))

except that the "closure" expression does not have the "self-quoting" property of a lambda, so when I try to evaluate it, Emacs informs me that closure has no function definition: Lisp error: (void-function closure).

I can't find any references in the Elisp manual to using the symbol closure in this way. It seems like some kind of internal Emacs magic. The closure expression is clearly not being evaluated according to the normal rules (since doing that manually gives an error).

So what's going on here? Do I need to grep the C code for references to "closure" to find out?

EDIT: It appears that in Emacs 23 and below, apply-partially simply uses the lexical-let from the cl package to make a closure. The definition above is from version "24.0.90.1".

like image 379
Ryan C. Thompson Avatar asked Oct 27 '11 08:10

Ryan C. Thompson


2 Answers

I found the answer in eval.c, in the funcall_lambda function:

  if (EQ (XCAR (fun), Qclosure))
{
  fun = XCDR (fun); /* Drop `closure'.  */
  lexenv = XCAR (fun);
  CHECK_LIST_CONS (fun, fun);
}
  else
lexenv = Qnil;

closure (t) appears to be the lexical equivalent of lambda. The second element, (t), gets assigned to lexenv, so I guess this element is for closing over lexical values defined outside of the function itself or something.

I suspect that the lack of self-quoting may be an oversight, which can be remedied as follows:

(defmacro make-self-quoting (name)
  "Make NAME into a self-quoting function like `lambda'."
  `(defmacro ,name (&rest cdr)
     (list 'function (cons ',name cdr))))
(make-self-quoting closure)
like image 186
Ryan C. Thompson Avatar answered Oct 04 '22 04:10

Ryan C. Thompson


With my "GNU Emacs 23.2.1 (i686-pc-cygwin)" it is defined as

(defun apply-partially (fun &rest args)
  "Return a function that is a partial application of FUN to ARGS.              
ARGS is a list of the first N arguments to pass to FUN.                         
The result is a new function which does the same as FUN, except that            
the first N arguments are fixed at the values with which this function          
was called."
  (lexical-let ((fun fun) (args1 args))
    (lambda (&rest args2) (apply fun (append args1 args2)))))

Understanding how it works seems to be quite easy here: The lambda remembers the partial set of args and appends the rest when calling the original function.

like image 43
Miserable Variable Avatar answered Oct 04 '22 04:10

Miserable Variable