而不是根据列表列表来思考,这可能是一个有用的地方,从根据对(也称为cons单元)构建的树来思考。当你打电话给(cons x y
时,你会收到一个反馈小组),x
被称为car
,而y
被称为cdr
。当你在某个对象object
搜索元素e
,你可以这样来做:
- 是
e
一样object
?如果是这样,你找到了!
- (a)
object
是一对吗?如果是这样,那么检查e
是(b)在其car
还是(c)在cdr
,如果是的话,那么你已经找到它了!
- 否则,你还没有找到它,它无处可寻。
这是比较直接翻译成代码,您甚至可以使用or
和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)
是(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))))))