当使用`:key`时,Common Lisp中的#'adjoin是否按照HyperSpec工作?

Adr*_*ian 3 lisp common-lisp ansi-common-lisp

查看HyperSpec中#'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))
Run Code Online (Sandbox Code Playgroud)

我希望以下内容:

(adjoin '(new-test-item 1) slist :key #'cadr) =>  ((NEW-TEST-ITEM 1) (TEST-ITEM 1))
Run Code Online (Sandbox Code Playgroud)

我的期望是由于HyperSpec(17.2.1)中的以下文本:

当通过下图中列出的运算符F对序列S的每个元素Ei迭代地考虑对象O时,有时控制在S中测试O的存在的方式由F测试.控制是基于用a:test或:test-not argument指定的函数提供的.

并进一步:

对象O可能无法直接与Ei进行比较.如果提供了:key参数,则它是一个参数的指示符,用于将每个Ei作为参数调用一个参数,并产生一个用于比较的对象Zi.(如果没有:关键参数,Zi就是Ei.)

由:key参数指定的函数永远不会在O本身上调用.但是,如果函数在多个序列上运行(例如,在set-difference中发生),则O将是在另一个序列的元素上调用:key函数的结果.

因此我们将sl(序列,S)'((TEST-ITEM 1))和O作为'(new-test-item 1).要检查是否应该连接O,该函数#'cadr将应用于S的元素,第一个是'(test-item 1).所以,那个测试给出了:

(cadr '(test-item 1)) => 1
Run Code Online (Sandbox Code Playgroud)

现在,当'(new-test-item 1)根据应用于#'cadrS的E1 的结果#'eql(当没有提供时使用的等式函数)检查O,时:test,false结果应该意味着O被连接.至少这就是我的想法.我有什么误会?

Jos*_*lor 6

这是HyperSpec中的一个错误,问题ADJOIN-SPECIFICATION已在CLiki上写过.相关部分是:

问题描述:

CLHS通过引用第17.2.1节"满足双参数测试"来指定存在于:KEY参数的ADJOIN行为.这是不正确的,因为第17.2.1节指定不在ITEM参数上调用键函数,但是ADJOIN在pushnew中指定.提案(ADJOIN:澄清):

更换:

test,test-not和key会影响如何确定item是否与list的元素相同.有关详细信息,请参见第17.2.1节(满足双参数测试).

通过:

项目是否已经是列表成员是通过比较使用:test或:test-not确定的.:test或:test-not函数的第一个参数是:key函数(如果提供)返回的结果,应用于项目; 第二个参数是:key函数(如果提供)返回的列表元素.如果:提供了密钥,则用于从项目和列表元素中提取要测试的部分.

理由:

澄清ADJOIN的规范.

目前的做法:

所有实现都按照pushnew上的指定实现ADJOIN,而不是在adjoin上指定.