2

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
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
Plakhoy
  • 1,846
  • 1
  • 18
  • 30
  • 1
    possible duplicate of [Why do we need funcall in lisp](http://stackoverflow.com/questions/9729549/why-do-we-need-funcall-in-lisp) – Joshua Taylor Oct 15 '13 at 12:43

3 Answers3

9

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")
Community
  • 1
  • 1
Lars Brinkhoff
  • 13,542
  • 2
  • 28
  • 48
6

Common Lisp has a separate namespace for functions, which makes operation like this more verbose than with Scheme. If you would like similar to top level (define p display) in CL you should make a macro:

(defmacro defun-alias (name original-name)
   `(setf (symbol-function ',name) #',original-name))

Which works as this:

(defun-alias pc princ)
(pc "Hello") ; prints hello

Unlike Scheme define this will only overwrite a global binding. Thus:

(flet ((test (x) (+ x x))) 
   (defun-alias test +)
   (test 10))

will set global definition of #'test to #'+ and return 20. eg. it works like defun.

Sylwester
  • 47,942
  • 4
  • 47
  • 79
5

To complement the other good answers with direct answers to your questions:

What does try using a symbol mean? p is definitely a symbol; false positive?

Read the error messages literally: (EVAL (ENVIRONMENT) P) and (EVAL P) (unevaluated) are not symbols, but lists. In Common Lisp, the car of a form is not evaluated.

What's up with eval? Doesn't the evaluation of p yield the procedure print?

eval is never called by your code (see previous answer). Even if it were, the result would be the symbol-value of the symbol print, not the symbol-function/fdefinition.

I thought Lisp procedures were first class objects. Why is Attempt 1 not working like in Scheme?

This has nothing to do with functions (I think the Common Lisp standard does not use the term "procedures" as the Scheme standards do.) being first class objects. This works in Common Lisp:

(let ((p #'print))
  (funcall p "hello world"))

Edit:

Answers to the extra questions:

I was wondering why (setf (symbol-function 'p) #'print) won't work this way (setf (symbol-function 'p) 'print).

It's not really true that "the sharp sign(#) is supposed to disambiguate between a function and a variable with the same name", as you write later. 'print expands to (quote print), so it evaluates to the symbol print instead of its value as a variable. #'print expands to (function print), so it evaluates to the value of the function cell of the symbol print instead. Whether print currently has a value as a variable is completely irrelevant to what #'print evaluates to.

Setting (symbol-function 'p) to the symbol print obviously won't make p call the function print because the symbol print is not the same as the function bound to the symbol print.

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.

setf assigns values to places. The term (symbol-function 'p) denotes the place that is the function cell of the symbol p.

defvar defines new global variables. Its first argument needs to be a symbol that names the variable and can not be any kind of place.

Rörd
  • 6,556
  • 21
  • 27
  • And, what is the answer to the question in the comment? – Plakhoy Oct 16 '13 at 20:16
  • Why aren't `car`s of forms evaluated? – Plakhoy Oct 16 '13 at 20:26
  • @Segfault: Here's the relevant section of the standard: http://www.lispworks.com/documentation/HyperSpec/Body/03_abab.htm. So actually, there are two valid types for the car of a form, symbols or lambda expressions. This would work: `((lambda (s) (funcall p s)) "hello world")`. – Rörd Oct 16 '13 at 20:56
  • @Segfault: Regarding your questions in the comments to LarsBrinkhoff's answer, please clarify what exactly is still unclear to you. – Rörd Oct 16 '13 at 20:58
  • Sorry if that was unclear. I've edited the question. – Plakhoy Oct 17 '13 at 08:18
  • @Segfault: I've added answers to the extra questions. – Rörd Oct 17 '13 at 08:53
  • I'm tempted to ask why said "it's not really true" but I'll try to find that out for myself. That's a beautiful answer, btw. – Plakhoy Oct 17 '13 at 13:12
  • @Segfault: I'll give you a short answer to that anyway. The Sharpsign is not activating a special mode of the Single-Quote reader macro. Single-Quote `'` and Sharpsign Single-Quote `#'` are two completely different reader macros. See this two sections of the standard: http://www.lispworks.com/documentation/HyperSpec/Body/02_dc.htm and http://www.lispworks.com/documentation/HyperSpec/Body/02_dhb.htm. – Rörd Oct 17 '13 at 13:17
  • @Segfault I'm surprised this answer isn't the accepted one. I thought it'd be the most helpful one, most detailed and directly specific. – Will Ness Oct 21 '13 at 05:44
  • I must confess, I was swayed by the votes. And yes @WillNess , it was the most helpful. I felt as if the others just answered and never checked back. It seems wrong to change it almost a week later though. – Plakhoy Oct 22 '13 at 08:06
  • @Segfault no, it's OK to change it whenever you feel like it's warranted to do so. We're supposed to accept the most helpful answer on SO, that's in the FAQ. :) – Will Ness Oct 22 '13 at 08:32