在Allegro CL和ABCL中,我可以构造一个仅给出其类型名称的结构吗?

时间:2015-05-04 12:33:03

标签: common-lisp allegro-cl abcl

在大多数实现中,无论是否为该类型定义构造函数,都可以使用(make-instance 'struct-type)创建结构。这不适用于Allegro或ABCL,但这些实现仍然可以在#S(struct-type)的读取时创建结构,这使我认为必须有其他方法在运行时构造它们,因为类型名称为一个符号。

3 个答案:

答案 0 :(得分:1)

您不应混合结构和对象创建。标准为standard-classsymbol定义make-instance,以便将提供的符号传递给find-class,然后make-instance递归。

因此,对于命名结构类型扩展make-instance的库存实现不符合要求,如果您依赖它,则代码也不符合。

然后,#S is specified只有在结构具有标准构造函数时才能正常工作,因此没有多少魔法。

鉴于此限制,您可以通过实现与结构名称连接的名为#S的符号,然后是关键字参数列表来实现make-

但同样,依赖于实现的细节会受到影响。您询问何时没有构造函数,这意味着:constructor nil中的defstruct。请注意,不指定构造函数参数意味着它将具有默认构造函数。该实现可以具有内部簿记,包括它创建的隐藏标准构造函数,而不管您在make-load-form-using-slots中使用的选项(或无参数构造函数和插槽访问器),扩展#S,并可能优化通过make-load-form对结构的专门化,在文件编译中加载文字结构(而不​​是创建一个的形式)。

答案 1 :(得分:0)

也许不是很优雅,但是关于:

(defun make-struct-by-name (name &rest args)
  (apply (symbol-function
          (intern (concatenate 'string "MAKE-"
                               (symbol-name name))))
         args))

用法:

CL-USER> (defstruct foo
           a b)
FOO

CL-USER> (make-struct-by-name 'foo :a 1 :b 2)
#S(FOO :A 1 :B 2)

答案 2 :(得分:0)

我想过一个可能的解决方案,但这有点像黑客攻击。由于#S阅读器宏可以工作,但我无法找到ABCL和Allegro如何实现它(它可能完全是内部的实现,而不是在Lisp中定义),我至少可以生成一个字符串并以编程方式调用读者宏功能就可以了:

(defun make-struct-from-type (type-name)
  (with-input-from-string
      (s (format nil "(~A::~A)"
                 (package-name (symbol-package type-name))
                 (symbol-name type-name)))
    (funcall (get-dispatch-macro-character #\# #\S)
             s #\S nil)))

但这可能不适用于其他实现。 SBCL抱怨sb-impl::*read-buffer*未被绑定,因此可能需要更多的诡计来欺骗实现,使其认为在典型的上下文中调用了读取器宏。

即使给出了没有默认make-前缀的名称,也应该调用默认构造函数。