3

In Common Lisp, I can get a function to pass around with the #' syntax, like this:

(let ((x #'+))
 (funcall x 1 2))

But suppose I want to set a function so I don't have to use funcall for it. Does Common Lisp have a local function name table, or just the global one that is assigned to with defun?

Is there a way to assign to a function symbol other than defun? Or more generally: is there a way I can do something similar to this nonworking example:

(setf #'x #'+)
(x 1 2)
sds
  • 58,617
  • 29
  • 161
  • 278
zstewart
  • 2,093
  • 12
  • 24

2 Answers2

12

You can define a local function using flet and labels:

(flet ((f (x) (1+ (* 2 x))))
  (f 7))
==> 15

You can also set function definition of a symbol using fdefinition:

(setf (fdefinition 'f) #'+)
(f 1 2 3)
==> 6

Note that let binds the value cell of the symbol while flet bind the function cell. When the symbol appears in the "function" position, the "function" cell is used, while when it appears in the "value" position, the "value" cell is used:

(setf (symbol-function 'x) #'car)
(setf (symbol-value 'x) #'cdr)
(x '(1 . 2))
==> 1
(funcall x '(1 . 2))
==> 2

Similarly,

(flet ((x (o) (car o)))
  (let ((x #'cdr))
    (cons (x '(1 . 2))
          (funcall x '(1 . 2)))))
==> (1 . 2)

This is the difference between Lisp-1 and Lisp-2.

Finally, note that CLISP is just one implementation of the language ANSI Common Lisp.

Community
  • 1
  • 1
sds
  • 58,617
  • 29
  • 161
  • 278
  • Is there something which is like a combination of `let` and `(setf (fdefinition ...))`? E.g. `(let ((x #'+)) (x 3 4)) ==> 7`, as in the original question? – zstewart Sep 16 '15 at 18:13
  • No, because Common Lisp is a [lisp-2](http://stackoverflow.com/q/4578574/850781). You would need scheme for that. – sds Sep 17 '15 at 01:54
  • But you could get this behavior by writing a macro that expands to `(flet ((x (&rest args) (apply f args))) (x 3 4))` given an input like `(this-macro ((x f)) (x 3 4))`, or something like that. – zstewart Oct 02 '15 at 19:12
0

One option for getting this kind of behavior is to write a macro to do it.

(defmacro flet* (assignments &body body)
  (let ((assignments (mapcar
                      (lambda (assn)
                        (list (first assn) '(&rest args)
                              (list 'apply (second assn) 'args)))
                      assignments)))
    `(flet ,assignments ,@body)))

This macro translates flet* into flet + apply like this:

(flet* ((x #'+)
        (y #'*))
       (pprint (x 1 2))
       (pprint (y 3 4))
       (pprint (x (y 2 3) 4)))

Becomes:

(flet ((x (&rest args) (apply #'+ args))
       (y (&rest args) (apply #'* args)))
       (pprint (x 1 2))
       (pprint (y 3 4))
       (pprint (x (y 2 3) 4)))
zstewart
  • 2,093
  • 12
  • 24