Commits

Aidan Kehoe committed b908c72

Add the #'apply-partially API, as used by GNU.

lisp/ChangeLog addition:

2011-08-12 Aidan Kehoe <kehoea@parhasard.net>

* cl-macs.el:
* cl-macs.el (apply-partially): New compiler macro.
* subr.el:
* subr.el (apply-partially): New.
Sync this function's API and docstring from GNU. The
implementation is mine and trivial; the compiler macro in
cl-macs.el ensures that partially-applied functions in compiled
code are also compiled.

tests/ChangeLog addition:

2011-08-12 Aidan Kehoe <kehoea@parhasard.net>

* automated/lisp-tests.el:
Trivial tests of #'apply-partially, just added to subr.el.

Comments (0)

Files changed (5)

+2011-08-12  Aidan Kehoe  <kehoea@parhasard.net>
+
+	* cl-macs.el:
+	* cl-macs.el (apply-partially): New compiler macro.
+	* subr.el:
+	* subr.el (apply-partially): New.
+	Sync this function's API and docstring from GNU. The
+	implementation is mine and trivial; the compiler macro in
+	cl-macs.el ensures that partially-applied functions in compiled
+	code are also compiled.
+
 2011-08-10  Aidan Kehoe  <kehoea@parhasard.net>
 
 	* keymap.el:
 	    (list 'let (list (list temp val)) (subst temp val res)))))
     form))
 
+(define-compiler-macro apply-partially (&whole form &rest args)
+  "Generate a #'make-byte-code call for #'apply-partially, if appropriate."
+  (if (< (length args) 1)
+      form
+    (if (cl-const-exprs-p args)
+        `#'(lambda (&rest args) (apply ,@args args))
+      (let* ((placeholders (mapcar 'quote-maybe (mapcar 'gensym args)))
+             (compiled (byte-compile-sexp
+                        `#'(lambda (&rest args) (apply ,@placeholders args)))))
+        `(make-byte-code
+          ',(compiled-function-arglist compiled)
+          ,(compiled-function-instructions compiled)
+          (vector ,@(sublis (pairlis placeholders args)
+                            (mapcar 'quote-maybe
+                                    (compiled-function-constants compiled))
+                            :test 'equal))
+          ,(compiled-function-stack-depth compiled))))))
+
 (define-compiler-macro delete-dups (list)
   `(delete-duplicates (the list ,list) :test #'equal :from-end t))
 
 quote lambda expressions appropriately."
   `(function (lambda ,@cdr)))
 
+;; Partial application of functions (related to currying).  XEmacs; closures
+;; aren't yet available to us as a language type, but they're not necessary
+;; for this function (nor indeed is CL's #'lexical-let).  See also the
+;; compiler macro in cl-macs.el, which generates a call to #'make-byte-code
+;; at runtime, ensuring that partially applied functions are byte-compiled.
+(defun apply-partially (function &rest args)
+  "Return a function that is a partial application of FUNCTION to ARGS.
+ARGS is a list of the first N arguments to pass to FUNCTION.
+The result is a new function which does the same as FUNCTION, except that
+the first N arguments are fixed at the values with which this function
+was called."
+  `(lambda (&rest args) (apply ',function ,@(mapcar 'quote-maybe args) args)))
+
 ;; FSF 21.2 has various basic macros here.  We don't because they're either
 ;; in cl*.el (which we dump and hence is always available) or built-in.
 
+2011-08-12  Aidan Kehoe  <kehoea@parhasard.net>
+
+	* automated/lisp-tests.el:
+	Trivial tests of #'apply-partially, just added to subr.el.
+
 2011-08-08  Stephen J. Turnbull  <stephen@xemacs.org>
 
 	* automated/syntax-tests.el:

tests/automated/lisp-tests.el

   (Assert (equal '([symbol expansion] [copy expansion] [third expansion])
 		 (test-symbol-macrolet))))
 
+;; Basic tests of #'apply-partially.
+(let* ((four 4)
+       (times-four (apply-partially '* four))
+       (plus-twelve (apply-partially '+ 6 (* 3 2))))
+  (Assert (eql (funcall times-four 6) 24))
+  (Assert (eql (funcall times-four 4 4) 64))
+  (Assert (eql (funcall plus-twelve (funcall times-four 4) 4 4) 36))
+  (Check-Error wrong-number-of-arguments (apply-partially)))
+
 ;;; end of lisp-tests.el