与其根据列表的列表来思考,这可能是一个有用的地方,可以根据由对(也称为 cons 单元)构建的树来思考。cons 单元格是您调用(cons x y
)时返回的内容,x
称为 its car
,y
称为 its cdr
。当您e
在某个对象中搜索元素时object
,您可以这样做:
- 是
e
一样的object
吗?如果是这样,你已经找到了!
- (a) 是
object
一对吗?如果是,那么检查e
是 (b) in itscar
还是 (c) in its cdr
,如果是,那么你已经找到了!
- 否则,你没有找到它,它也无处可寻。
or
将其转换为代码相对简单,您甚至可以使用and使其非常干净and
:
(define (tree-find e object)
(or (eq? e object) ; 1.
(and (pair? object) ; 2.a
(or (tree-find e (car object)) ; 2.b
(tree-find e (cdr object)))))) ; 2.c
现在,这甚至允许您在树中查找树的子部分。例如,如果你取出树'((1 2) (3 (4 5)) (6 7))
并提取它的第二个元素(列表(3 (4 5))
),并询问它是否是成员,你会得到肯定的答案。请注意,这是有效的,因为您正在检查eq?
,因此它只会找到相同的对象,而不仅仅是具有相同结构的对象:
(let* ((l '((1 2) (3 (4 5)) (6 7)))
(e1 (cadr l)) ; (3 (4 5)), from l
(e2 (list 3 '(4 5)))) ; (3 (4 5)), but not from l
(display (tree-find e1 l)) ; #t
(display (tree-find e2 l))) ; #f
然而,因为一个正确的列表被一个空列表终止(例如,(1 2 3)
is (1 . (2 . (3 . ())))
),如果输入中有一个正确的列表,tree-find
它将总是说它'()
是一个成员。因此,您可能希望明确禁止这种情况:
(define (tree-find e object)
(or (and (eq? e object)
(not (null? e))) ; check only non-null objects
(and (pair? object)
(or (tree-find e (car object))
(tree-find e (cdr object))))))