两个具有相同符号指示符的Common Lisp函数对象是否总是eq
?例如,这种比较似乎有效:
(defun foo (fn)
(let ((ht (make-hash-table)))
(eq (symbol-function (hash-table-test ht)) fn)))
FOO
* (foo #'eql)
T
*(foo #'equal)
NIL
但这可能依赖于未制作功能的潜在副本的实现,大概是出于效率方面的考虑。由于hash-table-test
返回一个符号指示符,另一个(可能更好)的eq替代方案是从函数对象中导出符号吗?一种方法比另一种更好吗?
答案 0 :(得分:4)
两个具有相同符号指示符的Common Lisp函数对象是否总是eq?
在Common Lisp中,函数是一段代码,无论是否编译。来自Glossary:
函数 n。 1.表示代码的对象,可以用零个或多个参数调用,并产生零个或多个参数价值观。 2.类型函数的对象。
另一方面,功能指示符可以是符号:
功能指示符 n。功能指示符;即,表示功能的对象,并且是以下各项之一:符号(表示在全局环境中由该符号命名的功能)或功能(表示自身)。
因此,作为功能指示符的符号是在特定上下文中或使用诸如#'symbol
或(function symbol)
之类的特定语法求值时产生一个功能,并且将两者进行比较的东西功能指示符是它们所表示的功能的比较:
CL-USER> (eql #'car #'cdr)
NIL
CL-USER> (eql #'car (symbol-function 'car))
T
但是请注意,此相等性测试只是功能对象(代码段)的标识的比较,例如:
CL-USER> (eq #'car #'car)
T
CL-USER> (let ((a (lambda (x) (1+ x))))
(eq a a))
T
但不代表它们的实际字节(代码!):
CL-USER> (let ((a (lambda (x) (car x)))
(eq a #'car))
NIL
CL-USER> (defun f (x) (1+ x))
F
CL-USER> (defun g (x) (1+ x))
G
CL-USER> (equalp (function f) (function g))
NIL
CL-USER> (equalp (lambda (x) (1+ x)) (lambda (x) (1+ x)))
NIL
请注意,在所有这些情况下,比较的两个函数不仅具有相同的“含义”,而且在大多数情况下具有相同的“源代码”,并且以相同的方式进行编译,并且在相同的输入数据上具有相同的行为。这是因为一个函数在数学上是(可能)成对的无限对(输入,输出),并且不能比较无限个对象。
但这可能依赖于未制作功能的潜在副本的实现,大概是出于效率方面的考虑。
用户无法复制函数(系统都没有理由执行一段代码的复制!),因此任何函数都与自身相等,就如同任何指针仅相等一样自己。
由于hash-table-test返回一个符号指示符,另一个(可能更好)的eq替代方案是从函数对象中派生符号吗?一种方法比另一种更好吗?
(我想您打算使用功能指示符,而不是符号指示符)
实际上,hash-table-test
通常仅以符号形式返回函数指定符,如manual中所述:
test ---功能指示符。对于四个标准化的哈希表测试功能(请参阅make-hash-table),返回的测试值始终是一个符号。如果实现允许其他测试,则是否以函数对象或函数名称返回测试取决于实现。
所以:
CL-USER> (type-of (hash-table-test (make-hash-table)))
SYMBOL
CL-USER> (eq 'eql (hash-table-test (make-hash-table)))
T
CL-USER> (eq #'eql (hash-table-test (make-hash-table)))
NIL
请注意,在最后一种情况下,我们正在将一个函数(#'eql
的值)与一个符号(hash-table-test
返回的值)进行比较,显然,该比较将返回一个假值。
结论:
比较函数不是很合理,除非您想知道两个函数实际上是否在内存中是同一对象(为方便起见,如果这两个对象是相同的编译代码)。
< / li>始终重要的是,将功能与其作为符号(功能名称)或列表(如(LAMBDA parameters body)
)的名称区别开来,并确定我们要实际比较的内容。
答案 1 :(得分:3)
#'eql
等效于(function eql)
。除非存在eql
的词法函数绑定,否则将其定义为返回符号eql
的全局函数定义。这也是(symbol-function 'eql)
定义要返回的内容。
因此,对于任何未被词法定义遮盖的全局定义函数f
,
(eq #'f (symbol-function 'f))
应始终为真。