Scheme 如何将函数存储在Lisp中的变量中并使用它

Scheme 如何将函数存储在Lisp中的变量中并使用它,scheme,common-lisp,eval,first-class-functions,lisp-2,Scheme,Common Lisp,Eval,First Class Functions,Lisp 2,我想在一个变量中存储一个函数,比如print,这样我就可以键入一些简短的东西,比如p,例如: 在方案中: (define print display) (print "Hello world\n") ;; alternate way (define print 'display) ((eval print) "Hello world\n") 同样的方法似乎不适用于通用Lisp: (defvar p 'print) ;;(print (type-of p)) (p "Hello world")

我想在一个变量中存储一个函数,比如
print
,这样我就可以键入一些简短的东西,比如
p
,例如:
方案中

(define print display)
(print "Hello world\n")
;; alternate way
(define print 'display)
((eval print) "Hello world\n")
同样的方法似乎不适用于
通用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
*** - 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
我在上面的
尝试1中遇到此错误:

*** - EVAL: undefined function P
Clisp
中使用
尝试2
3

(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
*** - 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
并与gcl一起

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

  • 尝试使用符号是什么意思
    p
    绝对是一个
    符号
    ;假阳性
  • 评估是怎么回事?对
    p
    的评估不产生程序
    print
  • 我认为
    Lisp
    过程是
    第一类对象
    。为什么
    尝试1
    不能像
    方案中那样工作
编辑
(摘自下面的评论)

我想知道为什么
(setf(符号函数'p)#'print)
不能以这种方式工作
(setf(符号函数'p')打印)
。我得到以下错误(不是很有帮助):

我知道尖锐的符号(
#
)应该用来消除函数和变量之间的歧义
使用相同的名称,但在本例中,只有一个
print
,即函数

另外,为什么它不使用
defvar
而不是像这样使用
setf

(defvar (symbol-function 'p) #'print)
然而
defvar
setf
都为变量赋值。
相关错误为:

*** - DEFVAR: non-symbol (SYMBOL-FUNCTION 'P) cannot be a variable ;; Clisp
Error: (SYMBOL-FUNCTION (QUOTE P)) is not of type SYMBOL. ;; Gcl
CommonLisp是一种语言。除此之外,函数调用中的第一个位置在“函数名称空间”中求值。在您的例子中,符号
p
命名的是变量,而不是函数

这样做效果更好:

(defvar p'打印)
(FUNCP“你好,世界”)
或者可能,但您可能不想这样做:

(setf(符号函数'p)#打印)
(p“你好,世界”)

Common Lisp为函数提供了一个单独的名称空间,这使得类似这样的操作比Scheme的操作更加冗长。如果您希望类似于CL中的顶级
(定义p显示)
,您应该制作一个宏:

(defmacro defun-alias (name original-name)
   `(setf (symbol-function ',name) #',original-name))
其工作原理如下:

(defun-alias pc princ)
(pc "Hello") ; prints hello
与Scheme
define
不同,这只会覆盖全局绑定。因此:

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

#'test
的全局定义设置为
#'+
并返回20。它的工作原理类似于
defun

以直接回答您的问题来补充其他好答案:

尝试使用符号意味着什么?p绝对是一个符号;假阳性

逐字阅读错误消息:
(EVAL(ENVIRONMENT)p)
(EVAL p)
(未评估)不是符号,而是列表。在Common Lisp中,不计算表单的car

eval怎么了?对p的评估不产生程序打印吗

eval
永远不会被您的代码调用(参见前面的答案)。即使是,结果也将是符号打印的
符号值,而不是
符号函数的定义

我认为Lisp过程是一流的对象。为什么尝试1不能像计划中那样工作

这与函数(我认为公共Lisp标准不像Scheme标准那样使用术语“过程”)作为一流对象无关。这适用于Common Lisp:

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

额外问题的答案:

我想知道为什么
(setf(符号函数'p)#'print)
不能以这种方式工作
(setf(符号函数'p')打印)

正如您稍后所写,“锐符号(#)应该用来消除函数和同名变量之间的歧义”,这并不是真的
'print
扩展为
(quote print)
,因此它计算为符号
print
,而不是作为变量的值
#'print
扩展为
(函数打印)
,因此其计算结果为符号
print
的函数单元格的值。
print
当前是否有一个值作为变量与
#print
的计算结果完全无关

(symbol function'p)
设置为符号
print
显然不会使
p
调用函数
print
,因为符号
print
与绑定到符号
print
的函数不同

另外,为什么它不能像这样使用defvar而不是setf:

然而,defvar和setf都为变量赋值

setf
为位置赋值。术语
(符号函数'p)
表示符号
p
的功能单元所在的位置


defvar
定义新的全局变量。它的第一个参数需要是一个命名变量的符号,不能是任何类型的位置。

考虑到这可能是局部范围,我还要指出
flet
标签
。我喜欢宏的可能重复,它接近
Scheme
定义
,并且,评论中问题的答案是什么?为什么不评估
car
s表单?@Segfault:以下是标准的相关部分:。实际上,有两种有效的形式,符号或lambda表达式。这将起作用:
((lambda)(funcall p s))“hello world”)
@Segfault:关于您在对LarsBrinkhoff回答的评论中提出的问题,请澄清您仍然不清楚的具体内容。如果不清楚,请道歉。我已经编辑了这个问题。