I need a procedure which takes a list and checks if an element is part of that list even when the list contains lists. So far, I\'ve written this:
(define (elem
Rather than thinking in terms of lists of lists, this may be a useful place to think in terms of a tree built from pairs (also known as cons cells). A cons cell is what you get back when you call (cons x y
), and x
is called its car
, and y
is called its cdr
. When you're searching for an element e
in some object object
, you can do it this way:
e
the same as object
? If so, you've found it!object
a pair? If so, then check whether e
is (b) in its car
or (c) in its cdr
, and if so, then you've found it!This is relatively straightforward to translate into code, and you can even make it pretty clean using 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
Now, this even allows you to find subparts of a tree within a tree. For instance, if you took the tree '((1 2) (3 (4 5)) (6 7))
and extracted its second element (the list (3 (4 5))
), and ask whether its a member, you'll get an affirmative answer. Note that this works because you're checking with eq?
, so it would only find the same object, not just one with the same structure:
(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
However, because a proper list is terminated by an empty list (e.g., (1 2 3)
is (1 . (2 . (3 . ())))
), tree-find
will always say that '()
is a member if there's a proper list in the input. As such, you might want to explicitly disallow that case:
(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))))))