问题
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 asymbol
; false positive? - What's up with
eval
? Doesn't the evaluation ofp
yield the procedureprint
? - I thought
Lisp
procedures werefirst class objects
. Why isAttempt 1
not working like inScheme
?
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
回答1:
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")
回答2:
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
.
回答3:
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.
来源:https://stackoverflow.com/questions/19375270/how-to-store-a-function-in-a-variable-in-lisp-and-use-it