与其根据列表的列表来思考,这可能是一个有用的地方,可以根据由对(也称为 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))))))