2

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

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

同样的方法似乎不适用于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

我在Attempt 1上面遇到了这个错误:

*** - EVAL: undefined function P

这与Attempt 23Clisp

*** - 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.

所以:

  • 是什么try using a symbol意思?p绝对是一个symbol;假阳性?
  • 怎么了eval?评估不p产生程序print吗?
  • 我以为Lisp程序是first class objects. 为什么Attempt 1不像在工作Scheme

编辑
(从下面的评论移动)

我想知道为什么(setf (symbol-function 'p) #'print)不能这样工作
(setf (symbol-function 'p) 'print)。我收到以下(不是很有帮助)错误:

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

我知道尖号(#)应该消除函数和
同名变量之间的歧义,但在这种情况下,只有一个print函数。

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

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

然而defvarsetf两者都为变量赋值。
相关的错误是:

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

3 回答 3

9

Common Lisp 是一个“Lisp-2”。除此之外,函数调用中的第一个位置是在“函数命名空间”中评估的。在您的情况下,符号p命名一个变量,而不是一个函数。

这效果更好:

(defvar p 'print)

(funcall p "Hello world")

或者可能,但您可能不想这样做:

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

(p "Hello world")
于 2013-10-15T07:48:51.397 回答
6

Common Lisp 有一个单独的函数命名空间,这使得这样的操作比使用 Scheme 更冗长。如果您想与 CL 中的顶级 (define p display)类似,您应该创建一个宏:

(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将设置to的全局定义#'+并返回 20。例如。它的工作原理像defun

于 2013-10-15T14:01:18.240 回答
5

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

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

从字面上阅读错误消息:(EVAL (ENVIRONMENT) P)(EVAL P)(未评估)不是符号,而是列表。在 Common Lisp 中,不评估表单的汽车。

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

eval永远不会被您的代码调用(请参阅上一个答案)。即使是这样,结果也会是symbol-value符号的print,而不是symbol-function/ fdefinition

我认为 Lisp 程序是一流的对象。为什么尝试 1 不像在 Scheme 中那样工作?

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

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

编辑

额外问题的答案:

我想知道为什么(setf (symbol-function 'p) #'print)不能这样工作 (setf (symbol-function 'p) 'print)

正如您稍后写的那样,“尖号 (#) 应该消除函数和同名变量之间的歧义”并不是真的。'print扩展为(quote print),因此它计算为符号print而不是其作为变量的值。#'print展开为(function print),因此它改为计算符号的函数单元格的值print。当前是否print将值作为变量与#'print评估结果完全无关。

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

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

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

然而 defvar 和 setf 都给变量赋值。

setf为地点赋值。该术语(symbol-function 'p)表示作为符号功能单元的位置p

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

于 2013-10-16T17:54:32.853 回答