查看HyperSpec中的docs for #'adjoin,我在示例部分看到以下内容:
(setq slist '()) => NIL
(setq slist (adjoin '(test-item 1) slist)) => ((TEST-ITEM 1))
(adjoin '(new-test-item 1) slist :key #'cadr) => ((TEST-ITEM 1))
我原本期望以下内容,而不是:
(adjoin '(new-test-item 1) slist :key #'cadr) => ((NEW-TEST-ITEM 1) (TEST-ITEM 1))
我的期望是由于HyperSpec (17.2.1)中的以下文字:
当对象O被迭代地考虑每个元素时 在下图中列出的运算符F的序列S的Ei是 有时控制O的存在方式很有用 在S中测试的是由F.测试的。该控制是在a的基础上提供的 用以下函数指定的函数:test或:test-not argument。
并且,进一步:
对象O可能无法直接与Ei进行比较。如果是:key参数 提供,它是一个参数的函数的指示符 用每个Ei作为参数调用,并产生一个对象Zi 用于比较。 (如果没有:关键参数,Zi就是Ei。)
从不在O上调用由:key参数指定的函数 本身。但是,如果函数在多个序列上运行(例如, 正如在set-difference中所发生的那样,O将是调用的结果 :关键函数在另一个序列的元素上。
所以我们将(序列,S)设为'((TEST-ITEM 1))
,将O设为'(new-test-item 1)
。要检查是否应该连接O,函数#'cadr
将应用于S的元素,第一个是'(test-item 1)
。所以,那个测试给出了:
(cadr '(test-item 1)) => 1
现在,当检查O '(new-test-item 1)
时,检查#'cadr
对带有#'eql
的S的E1的结果(当:test
没有提供时使用的等式函数}),false
结果应该表示O是相邻的。至少这就是我的想法。我误解了什么?
答案 0 :(得分:6)
这是HyperSpec中的一个错误,并且已经在CLiki上编写了Issue ADJOIN-SPECIFICATION。相关部分是:
问题描述:
CLHS通过引用第17.2.1节“满足a”来指定存在于:KEY参数的ADJOIN行为 双参数测试。这是不正确的,因为第17.2.1节规定了 没有在ITEM参数上调用键函数,而是调用ADJOIN 如pushnew中所指定的那样。提案(ADJOIN:澄清):
替换:
测试,测试 - 不和关键影响如何确定项目 与列表元素相同。有关详细信息,请参见第17.2.1节 (满足双论证测试)。
由:
项目是否已经是列表的成员是由 比较使用:test或:test-not。第一个参数:test 或:test-not函数是:key函数返回的结果(如果 提供),适用于该项目;第二个参数是一个元素 由:key函数返回的列表(如果提供)。如果:关键是 提供,它用于从两个项目中提取待测部件 和列表元素。
理由:
澄清ADJOIN的规范。
目前的做法:
所有实现都按照pushnew上的指定实现ADJOIN,而不是在adjoin上指定。