2

I recently started to learn CL, and I'm trying to figure out if I can set a value to a symbol in the function namespace.

I'd like to just define functions in terms of function composition, or simply by an existing function (e.g. I just had to rewrite identity twice in a toy "Hello, World!" level project). I'm not sure if it's even possible since it might break the namespace separation (at least without enforcement). I also tried to macroexpand what defun actually does; it's too cryptic to me as a beginner but it seems like the core part of it is built-in (I'm using SBCL).

So e.g. instead of saying:

(defun myfn (x) x)

I'd rather just say:

(def..? myfn identity)

If I can't do that, how can I avoid this class of code duplication? (which includes functions created by function composition, not just creating synonyms).

MasterMastic
  • 20,711
  • 12
  • 68
  • 90
  • Just an idea, you could add a macro which expands to `(defun myfun (&rest args) (apply identity args))`. Of course, in a Lisp-1, you could just `(define myfn identity)`. – Cactus Mar 22 '16 at 03:39
  • 2
    Be sure to have a look at some of the functions linked from the duplicate, too. There's lots of useful information floating around. The one titled **why defun is not the same as (setq )?** has some good discussion. – Joshua Taylor Mar 22 '16 at 11:26
  • 1
    Also, just to be clear, you can get the function value of a symbol using the `#'` notation. I.e., you don't need to do `(let ((id (lambda (x) x))) (compose id ...))`. You can just do `(let ((id #'identity)) (compose id ...))` or `(compose #'identity ...)`. – Joshua Taylor Mar 22 '16 at 12:23

1 Answers1

5

That's possible for functions bound to symbols, in the current environment:

(setf (symbol-function 'myfn) #'identity)

There is also (setf FDEFINTION) which does mostly the same, but also supports setf functions.

One can't do it for lexically bound functions (by FLET and LABELS).

Example how to set a symbol function using (setf fdefinition)

CL-USER 11 > (setf (fdefinition 'myfn) #'identity)
#<Function IDENTITY 410003F974>

CL-USER 12 > (myfn 10)
10

Further remarks

Note that it does that in the current environment. Thus

(defun myfn (x) x)

might be replaced by something like

(eval-when (:compile-toplevel :load-toplevel :execute)
  (setf (fdefinition 'myfn) #'identity))

Tha advantage: the function would be known as usual during compilation.

One of the things to keep in mind:

The symbol object may carry some information. For example the original function name, if there was one:

CL-USER 13 > #'identity
#<Function IDENTITY 410003F974>

Setting the function cell of a symbol, does not change that:

CL-USER 14 > #'myfn
#<Function IDENTITY 410003F974>

It's the same function object with its original internal name. One may be able to access that name, but one can't change it:

CL-USER 18 > (nth-value 2 (function-lambda-expression #'identity))
IDENTITY

There is also a problem with self-recursive functions:

CL-USER 19 > (defun foo (n)
               (if (zerop n)
                   1
                 (* n (foo (1- n)))))  ; here foo calls the function foo
FOO

now we set BAR to use the function FOO

CL-USER 20 > (setf (symbol-function 'bar) #'foo)
#<interpreted function FOO 4060004084>


CL-USER 21 > (bar 10)
3628800

Here we redefine FOO:

CL-USER 22 > (defun foo (n)
               (if (zerop n)
                   1
                 (+ n (foo (1- n)))))
FOO

BAR still uses the old FOO, which may or may not call the new FOO.

CL-USER 23 > (bar 10)
460

OOPS! We changed FOO, but it has strange effects on BAR: the first iteration is the old FOO and the next recursive invocation is the new FOO.

BAR and FOO are two different versions of the same function. But both call the function FOO, which may be the old or the new function - depending on how you interpret or compile the code.

CL-USER 24 > #'foo
#<interpreted function FOO 40600041F4>

CL-USER 25 > #'bar
#<interpreted function FOO 4060004084>
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346