Search code examples
schemecommon-lispevalfirst-class-functionslisp-2

How to store a function in a variable in Lisp and use it


I want to store a function like print in a variable so that I can just type something short like p, e.g:
In Scheme:

(define print display)
(print "Hello world\n")
;; alternate way
(define print 'display)
((eval print) "Hello world\n")

The same approach does not seem to work in Common Lisp:

(defvar p 'print)
;;(print (type-of p))
(p "Hello world") ;; Attempt 1
((eval p) "Hello world") ;; >> Attempt 2
((eval (environment) p) "Hello world") ;; Attempt 3

I'm getting this error with Attempt 1 above:

*** - EVAL: undefined function P

And this with Attempt 2 and 3 in Clisp:

*** - EVAL: (EVAL (ENVIRONMENT) P) is not a function name; try using a 
            symbol instead
*** - EVAL: (EVAL P) is not a function name; try using a symbol instead

And with gcl:

Error: (EVAL P) is invalid as a function.
Error: (EVAL (ENVIRONMENT) P) is invalid as a function.

So:

  • What does try using a symbol mean? p is definitely a symbol; false positive?
  • What's up with eval? Doesn't the evaluation of p yield the procedure print?
  • I thought Lisp procedures were first class objects. Why is Attempt 1 not working like in Scheme?

EDIT
(Moved from a comment below)

I was wondering why (setf (symbol-function 'p) #'print) won't work this way
(setf (symbol-function 'p) 'print). I get the following(not so helpful) error:

*** - SYSTEM::%PUTD: PRINT is not a function ;; CLisp
Error: PRINT is not of type LIST. ;; Gcl

I know that the sharp sign(#) is supposed to disambiguate between a function and a variable
with the same name but in this case, there's only one print, the function.

Also, why won't it work with defvar instead of setf like so:

(defvar (symbol-function 'p) #'print)

yet defvar and setf both assign values to a variable.
The associated error is:

*** - DEFVAR: non-symbol (SYMBOL-FUNCTION 'P) cannot be a variable ;; Clisp
Error: (SYMBOL-FUNCTION (QUOTE P)) is not of type SYMBOL. ;; Gcl

Solution

  • Common Lisp is a "Lisp-2". Among other things, the first position in a function call is evaluated in the "function namespace". In your case, the symbol p names a variable, not a function.

    This works better:

    (defvar p 'print)
    
    (funcall p "Hello world")
    

    Or possibly, but you probably don't want to do this:

    (setf (symbol-function 'p) #'print)
    
    (p "Hello world")