Common lisp 在Allegro CL和ABCL中,我可以只给出结构的类型名来构造结构吗?

Common lisp 在Allegro CL和ABCL中,我可以只给出结构的类型名来构造结构吗?,common-lisp,allegro-cl,abcl,Common Lisp,Allegro Cl,Abcl,在大多数实现中,您可以使用(make instance'struct type)创建结构,而不管您是否为该类型定义了构造函数。这在Allegro或ABCL上不起作用,但这些实现仍然可以在读取时使用#S(结构类型)创建结构,这让我认为,如果使用类型名称作为符号,则必须有其他方法在运行时构建结构。不应该将结构和对象创建混为一谈。为标准类和符号定义的标准,以便将提供的符号传递给查找类,然后生成实例递归 因此,为命名结构类型扩展make instance的stock实现是不一致的,如果依赖它,代码也是不

在大多数实现中,您可以使用
(make instance'struct type)
创建结构,而不管您是否为该类型定义了构造函数。这在Allegro或ABCL上不起作用,但这些实现仍然可以在读取时使用
#S(结构类型)
创建结构,这让我认为,如果使用类型名称作为符号,则必须有其他方法在运行时构建结构。

不应该将结构和对象创建混为一谈。为
标准类
符号
定义的标准,以便将提供的符号传递给
查找类
,然后
生成实例
递归

因此,为命名结构类型扩展
make instance
的stock实现是不一致的,如果依赖它,代码也是不一致的

然后,只有在结构具有标准构造函数的情况下才能正确工作,因此没有多少魔力了

鉴于此限制,您可以通过插入名为
make-
的符号(与结构名称连接,后跟关键字参数列表)自行实现
#S


但是,依赖于实现的细节再次受到影响。您询问何时没有构造函数,这意味着
defstruct
中的
:构造函数nil
。注意,不指定构造函数参数意味着它将有一个默认构造函数。该实现可以具有内部簿记功能,包括它创建的隐藏标准构造函数(或无参数构造函数和插槽访问器),扩展的
#S
,以及可能优化文本结构加载(与创建文本结构的表单相反)通过的结构专门化进行文件编译。

可能不是很优雅,但关于:

(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)

我想到了一个可能的解决方案,但这有点像黑客。由于
#的
读卡器宏可以工作,但我无法找到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-
前缀。

所以如果我没看错的话,就没有办法要求提供可用构造函数的列表了?我也想听听您对我提出的解决方案的看法:您到底想实现什么?生成测试数据的声明性规范:。我希望通过简单、可移植的方式通过内省获取我需要的信息,但如果归结到这一点,我准备秘密处理每个实现。SBCL行为是一个bug。如您所示,您可能希望在读取器上下文之外执行分派宏角色的函数。一种解决方法是使用
(read s)
,而不是自己调用dispatch宏字符函数。即使如此,这也可以创建结构,但不能初始化。