我需要一个过程,它接受一个列表并检查一个元素是否是该列表的一部分,即使该列表包含列表。到目前为止,我写过:
(define (element-of-set? element set)
(cond ((null? set) #f)
((eq? element (car set)) #t)
(else (element-of-set? element (cdr set))))))
但是,如果你有一个如下所示的列表:
(a (a b b (c b) 3) 5 5 (e s) (s e s))
然后我的书面element-of-set?
无法识别3是此列表的一部分。我做错了什么?
答案 0 :(得分:0)
您不会在car
论证的set
内重复出现。
如果您评估
(element-of-set? 3 '(a (a b b (c b) 3) 5 5 (e s) (s e s)))
根据您当前的element-of-set?
定义,它会执行类似
(eq? 3 'a)
,nope。(eq? 3 '(a b b (c b) 3))
,nope。(eq? 3 5)
,不是(eq? 3 5)
,不是(eq? 3 '(e s))
,不是(eq? 3 '(s e s))
,nope。3
不是'(a (a b b (c b) 3) 5 5 (e s) (s e s))
如果要检查深层集合成员资格,则需要重新定义您的过程,以便在car
set
list
时,如果该元素本身为...
((list? (car set)) (or (element-of-set? element (car set))
(element-of-set? element (cdr set))))
...
。像
list?
应该这样做,假设实际定义了(not (atom? (car set)))
(我在这台机器上没有方案解释器,所以我不确定。你可能需要使用{{1}}代替。) / p>
答案 1 :(得分:0)
不是根据列表列表进行思考,而是根据从对(也称为cons单元)构建的树进行思考,这可能是一个有用的地方。当您致电(cons x y
)时,您会收到一个缺点,而x
被称为car
,y
被称为cdr
。当您在某个对象e
中搜索元素object
时,您可以这样做:
e
与object
相同吗?如果是这样,你就找到了它!object
是一对吗?如果是,请检查e
中的car
是否为(b),cdr
中是否为(c),如果是,则表示您已找到它!转换为代码相对简单,您甚至可以使用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))))))
答案 2 :(得分:0)
您只需要另一个子句来检查car
是否为列表。将其添加到您的cond
(在eq?
子句之后):
((list? (car set))
(or (element-of-set? element (car set))
(element-of-set? element (cdr set))))
这会对任何子列表进行处理。