来自 listp 的意外结果

Ste*_*rus 1 lisp predicate common-lisp

我有一个结构蜘蛛:

(defstruct spider omegas values k)
Run Code Online (Sandbox Code Playgroud)

和一个实例蜘蛛

(set '*spider* (make-spider
  :omegas '()
  :values (list *input*)
  :k '(#'omegashift #'dec #'dupval '((0 . #'dec) (1 . #'inc) (2 . #'dec)))))
Run Code Online (Sandbox Code Playgroud)

但是当我运行表达式时:(listp (car (spider-k *spider*))在 Emacs 和 SBCL 上(并且涉及 SLIME,但我不确定它是什么。)REPL 返回T. 这显然令人困惑,因为(car (spider-k *spider*)正确返回#'OMEGASHIFT(listp (function OMEGASHIFT))正确返回NIL

为什么是(listp (car (spider-k *spider*))真的?不应该是假的吗?

Bar*_*mar 6

#'omegashift是一个扩展到 list 的读取器宏(function omegashift)

当您评估时,(function omegashift)您会得到一个函数,但您并未评估它,因为您引用了列表。所以你只是得到了读取器宏扩展到的列表。

如果你这样做,你会看到同样的事情(listp (car '('foo)))'foo扩展到列表(quote foo)。这计算为符号foo,但列表前的引号阻止计算。

要获取函数而不是列表,您需要计算函数表达式。您可以通过调用函数list而不是引用列表来做到这一点。

(setq *spider* (make-spider
  :omegas '()
  :values (list *input*)
  :k (list #'omegashift #'dec #'dupval (list (cons 0  #'dec) (cons 1  #'inc) (cons 2  #'dec)))))
Run Code Online (Sandbox Code Playgroud)

您还可以使用反引号来简化此操作:

(setq *spider* (make-spider
  :omegas '()
  :values (list *input*)
  :k `(,#'omegashift ,#'dec ,#'dupval '((0 . ,#'dec) (1 . ,#'inc) (2 . ,#'dec)))))
Run Code Online (Sandbox Code Playgroud)

在反引号表达式中,您使用逗号来标记要计算的子表达式。

顺便说一句,您应该使用setq分配变量,而不是set使用带引号的符号。它们对于全局变量是等价的,但不能set与局部变量一起使用。

  • 使用 defvar 声明全局变量就不会报错。 (6认同)