Lambda函数是否为CLOS对象?相关技术疑问
问题背景
执行以下Lisp代码:
(defparameter thing #'(lambda () (+ 1 1)))
变量thing的返回输出为:
#<FUNCTION (LAMBDA ()) {53A11BEB}>
该输出风格和CLOS的print-object输出极为相似,因此希望查看print-object的具体实现细节,但在自定义的list-class-slots函数中,无法确定正确的函数对象类名称:
(defun list-class-slots (class) (mapcar #'sb-mop::slot-definition-name (sb-mop::class-direct-slots (class-of (make-instance class)))))
尝试使用sb-mop::funcallable-standard-class作为参数时返回nil,使用function时则报错提示应使用funcallable-standard-class。由此产生疑问:
- 我的思路是否有误?
- 最初的lambda输出是否与CLOS完全无关?
- 若无关,该输出的来源是什么?
解答
思路偏差点
你的思路方向没错,但操作方式有误。Lambda创建的函数对象确实属于CLOS体系,但不能通过make-instance去实例化它的类——函数对象的创建是由Lisp系统内部完成的,lambda表达式、defun定义的函数都是系统自动生成funcallable-standard-class的实例,常规make-instance调用对这个类无效,这也是你用sb-mop::funcallable-standard-class参数返回nil的原因。Lambda输出与CLOS的关联
那个输出格式确实来自CLOS的print-object机制。所有CLOS实例的默认打印格式都是#<类名 {对象ID}>的风格,函数对象作为funcallable-standard-class的实例,自然遵循这个规则,所以两者的输出风格一致是必然的。正确获取函数对象的类信息
不需要通过make-instance创建实例,直接用已有的函数对象thing来获取类信息即可,修改后的代码如下:
(mapcar #'sb-mop::slot-definition-name (sb-mop::class-direct-slots (class-of thing)))
执行这段代码就能拿到该函数对象类的直接槽名称。
- 关于
function参数报错的原因function是Common Lisp内置的类型符号,并非CLOS类对象,而make-instance要求传入的是CLOS类对象,因此用它作为参数会报错,这是概念混淆导致的错误。
总结:Lambda生成的函数对象确实是CLOS中funcallable-standard-class的实例,输出格式来自CLOS的print-object,你之前的问题出在错误尝试用make-instance实例化函数类,正确做法是直接使用已存在的函数对象获取类信息。
内容的提问来源于stack exchange,提问作者Vinn

