首页 > 解决方案 > 为什么在 `let` 中调用 `make-instance` 的工作方式不同?

问题描述

我正在探索 Common Lisp 语法的一些可能性,并且我想在某些情况下创建一个:around方法make-instance来返回一些任意值。为简单起见nil,当我没有传递所需的参数时,就让它成为吧。它有效,但在调用 let 时无效:

(defclass foo ()
  ((bar :initarg := :initform '())))

(defmethod make-instance :around ((type (eql 'foo)) &key =)
  (if (not =) nil (call-next-method)))

(print (make-instance 'foo))    ;; => NIL

(print (let ((x (make-instance 'foo))) x)) ;; => #<FOO {10037EEDF3}> 

有人可以解释这种情况吗?为什么呢?SBCL 是试图变得聪明,还是实际上是标准的事情?我知道我可以通过使用 apply 来解决它:

(print (let ((x (apply #'make-instance (list 'foo)))) x)) ;; => NIL

但我不想依赖这种解决方法。实际上,我可以为此使用常规功能,这没关系,但我想了解它为什么会这样工作以及是否可以禁用这种行为。

标签: common-lispsbclletclos

解决方案


看起来像是MAKE-INSTANCESBCL(-> CTOR)中常量类名的优化尝试之一......

这似乎有效:

(defmethod make-instance :around ((class (eql (find-class 'foo)))
                                  &rest initargs
                                  &key =
                                  &allow-other-keys)
  (declare (ignorable initargs))
  (if (not =) nil (call-next-method)))

但询问 SBCL 专家或提交错误报告可能很有用......


推荐阅读