[当浏览Bert Burgemeister的“ Common Lisp快速参考”时,我偶然发现了tailp
。
首先,我误解了此函数的定义。我尝试过:
(tailp '(3 4 5) '(1 2 3 4 5))
但它返回了
NIL
CLTL2说,tailp
为真iff第一个参数是具有现有(nthcdr n list)
的任何n
。
(nthcdr 2 '(1 2 3 4 5))
;; (3 4 5)
我进一步尝试过:
(tailp '(3 4 5) '(1 2 3 4 5))
;; NIL - and I would expect: T following the definition above.
(tailp '() '(1 2 3 4 5))
;; T
(tailp '5 '(1 2 3 4 . 5))
;; T
直到我尝试过(然后才理解tailp
寻找cdr
的l
甚至共享相同的地址):
(defparameter l '(1 2 3 4 5 6))
(tailp (nthcdr 3 l) l)
;; T
但是随后我有下一个问题:
For what such a function is useful at all?
不是一个更有用的函数,它看起来子列表是否是列表的一部分? (或者看起来像列表的一部分,而不是它必须共享相同的地址?)
备注:
嗯,慢慢地,我开始理解,也许这是列表的eq
部分的cdr
...种类...“给定列表cdr
的任何eq
派生词到第一个参数?”
但是也许有人可以向我解释这种测试在哪些情况下非常有用?
在与@Lassi here的长时间讨论中,我们发现:
切勿在通函列表上使用tailp
!
因为该行为未定义(在SBCL中已经出现问题)。因此,tailp
用于非循环列表。
tailp
的基本目的是检查是否存在共享的列表结构。这意味着cons单元格是否相同(这意味着EQL
作为谓词)-不仅仅是cons单元格的内容。
也可以检查项目是否位于最后一个cdr
中:
CL-USER 87 > (tailp t '(1 2 3 4 . t))
T
CL-USER 88 > (tailp nil '(1 2 3 4 . nil))
T
CL-USER 89 > (tailp nil '(1 2 3 4))
T
CL-USER 90 > (tailp #1="e" '(1 2 3 4 . #1#))
T
这是Common Lisp中很少使用的功能之一。
[我很确定(tailp '(3 4 5) '(1 2 3 4 5))
的答案可以是t
和nil
,因为智能编译器可能会做(tailp '#1=#(3 4 5) '(1 2 . #1#))
以减少内存占用。引用的内容是不可变的文字,所以为什么不两次使用相同的内存?
tailp
的工作方式是:
(defparameter *tail* (list 3 4 5))
(defparameter *larger* (list* 1 2 *tail*))
(defparameter *replica* (copy-list *larger*))
(tailp *tail* *replica*) ; ==> nil
(tailp *tail* *larger*) ; ==> t
由于copy-list
将为其共享的列表中的每个元素创建新的缺点除了空列表和其他列表外,什么都没有。它是唯一的。
[*larger*
已与*tail*
制成共同尾号,因此(tailp *tail* *larger*)
将为t
。
重要的是,将参数作为相同的对象进行比较。由于尾部不必是列表,因此它与eql
进行比较。比较东西是否相同时,请使用equal
,因此tailp
的含义更为具体。它必须是等于(eq
)或eql
原子值的指针。
那么您在哪里使用呢?我在考虑一个功能性数据结构,您通常在其中重用共享结构。 tailp
可能用于标识父级的子树。基本上,这是一个性能更高的版本:
(defun my-tailp (needle haystack)
(cond ((eql needle haystack) t)
((atom haystack) nil)
(t (my-tailp needle (cdr haystack)))))
这里是tailp
有用的情况:
(defun circular-list-p (l)
(and (consp l)
(tailp l (rest l))))
一些注意事项。
这在所有情况下都会终止:如果第一个参数不是第二个参数的末尾(即,不需要检查它的圆形性),则允许tailp
在循环列表上不终止,但是如果第一个参数则必须终止。 是秒尾。但是,如果列表是循环的,那正是我们在此处检查的内容,因此它将终止。 (我对此感到困惑了一段时间。)>
consp
检查为(circular-list-p nil)
为假:我认为这是实用的选择,尽管您的学徒可能会认为nil
是圆形的。
@@ Sylwester: