Search code examples
functionlambdaschemeelisplisp-2

Can Emacs Lisp assign a lambda form to a variable like Scheme?


While investigating Emacs Lisp's symbol cells, I found out that for an example function like

(defun a (&rest x)
    x)

I can call (symbol-function 'a), which returns (lambda (&rest x) x). I can then use it if I want

> ((lambda (&rest x) x) 1 2 3 4 5)
(1 2 3 4 5)

which has the same functionality as the original function above. Now, this reminds me of Scheme where a lambda expression is the body of the function and is assigned to a variable name with Scheme's all-purpose define. For example

(define atom?
    (lambda (x)
        (and (not (pair? x)) (not (null? x)))))

simply assigns the lambda expression to atom? -- and now atom? is a function. So can elisp do this, i.e., assign a lambda expression to a symbol and then use it as a function? I've tried

(setq new-a (lambda (&rest x) x))

which gives (void-function new-a) if I try to use it as a function. Is there a way to imitate the Scheme world on this issue? It seems like there must be a way. Why else would the function cell of a contain (lambda (&rest x) x) if we couldn't turn this lambda expression into a function?


Solution

  • An important difference between scheme and emacs lisp (and indeed most other lisps) is that scheme has a single namespace whereas emacs lisp has separate namespaces for functions and variables. The first position in a list form that is evaluated names a function and that name is looked up in the function name space. In scheme, all names live in the same space, the value bound to the name is looked up and used whereever it appears.

    This means that in emacs lisp you can something like this:

    (defun f (x) (+ x x))
    (setq f 2)
    (f f) ;=> 4
    

    This is not possible in scheme, here there would be only one f and if you set its value, it would change from (say) a function to a number.

    There are different ways of handling this in emacs lisp.

    One is to use functions such as funcall and apply, these takes a function and some arguments and apply the function to the arguments, as in:

    (setq f (lambda (x) (+ x x)))
    (funcall f 2) ;=> 4
    

    Another approach is to manipulate what the function name f means. There is a function called fset that allows you to attach functions to names (in the function namespace):

    (fset 'f (lambda (x) (+ x x x)))
    (f 2) ;=> 6
    

    Note that fset works on names (aka symbols) so the name f needs to be quoted, otherwise it would be read as the value of a variable. That is why the function to a variable is called setq, the "q" stands for "quoted" so setq is actually a special function that quotes its first argument, so that the programmer does not have to do it. There is an equivalent normal function called set that does not do any quoting, as in:

    (setq x 1)  ; x is 1
    (set 'x 2)  ; x is 2
    (setq x 'x) ; x is the symbol x
    (set x 3)   ; x is now 3
    

    The last form may look confusing but as set is a normal form, it will look up the value of the variable x, that value is the symbol x and that then names the variable that will be changed (i.e. x). Thus one advantage of set is that it is possible to set variables whose name you do not know but rather commutes.