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

时间:2014-03-12 17:28:12

标签: lisp common-lisp ansi-common-lisp

查看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是相邻的。至少这就是我的想法。我误解了什么?

1 个答案:

答案 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上指定。