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 (element-of-set? element set)
(cond ((null? set) #f)
((eq? element (car set)) #t)
(else (element-of-set? element (cdr set))))))
But, if you have a list that looks like this:
(a (a b b (c b) 3) 5 5 (e s) (s e s))
then my written element-of-set?
does not recognize that 3 is a part of this list. What am I doing wrong?
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
), andx
is called itscar
, andy
is called itscdr
. When you're searching for an elemente
in some objectobject
, you can do it this way:e
the same asobject
? If so, you've found it!object
a pair? If so, then check whethere
is (b) in itscar
or (c) in itscdr
, 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
andand
: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 witheq?
, so it would only find the same object, not just one with the same structure: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:You're not recurring down the
car
of yourset
argument.If you evaluate
with your current definition of
element-of-set?
, it'll do something like(eq? 3 'a)
, nope.(eq? 3 '(a b b (c b) 3))
, nope.(eq? 3 5)
, nope(eq? 3 5)
, nope(eq? 3 '(e s))
, nope(eq? 3 '(s e s))
, nope.3
is not a member of'(a (a b b (c b) 3) 5 5 (e s) (s e s))
If you want to check for deep set membership, you need to redefine your procedure so that it recurs into the
car
ofset
if that element is itself alist
. Something likeshould do it, assuming
list?
is actually defined (I don't have a scheme interpreter on this machine, so I'm not sure. You may need to use(not (atom? (car set)))
instead).You just need another clause to check if the
car
is a list. Add this to yourcond
(after theeq?
clause):This recurses on any sublists.