如何检查Scheme中两个列表的结构相等?例如,(a (b) (c d))
等于(a b (c d) (e f g))
,(a b)
等于(a b c)
。列表中的 data 内容无关紧要,只有嵌套列表的结构层次结构,即子列表的数量,以及这些子列表的子列表数量等等。
我创建了一个名为eqStruct
的函数,它将两个列表作为参数。它应该计算每个列表中的子列表数量a
和b
,然后返回一个布尔值。该函数查看列表a
的每个元素,然后查看列表b
的每个元素。它使用c
和d
分别作为a
和b
中子列表数量的计数器,当atom?
在调用时返回false时,它们会递增列表的元素。在每次查看列表的第一个原子之后,列表被设置为相等而没有第一个项目(list-tail),并且unless
循环在整个列表'a和'b已经被终止时终止看着。
(define (eqStruct 'a 'b)
(define c 0)
(define d 0)
(define (atom? x) (not (pair? x)))
(unless (null? a)
(unless (atom? (first a)) (set! c (+ c 1))
(set! a (list-tail a 1))
)
(unless (null? b)
(unless (atom? (first b)) (set! d (+ d 1))
(set! b (list-tail b 1))
)
(eq? c d)
)
最后一行应该是一个return语句,因为我希望函数是一个谓词,并返回列表是否具有相同的结构,一个布尔值,但我不知道如何实现这一点,或者如果我以正确的方式思考这个问题。
答案 0 :(得分:4)
您的代码(以及您对它的评论)指出了对某些Racket结构的一些误解。
一个大问题是unless
不是循环结构;它只是有条件地执行一些代码。例如,如果您评估(unless (= 1 2) (display 'x))
,则不会永久打印x
,而只需打印一次。这意味着您获得的代码将不会按照您的预期执行。
但是,如果我们假设那是(以便我们了解您的代码尝试做什么),那么您就有了一个合理的想法。您正试图迭代列表a
并计算它所包含的元素数量。
(unless (null? a)
(unless (atom? (first a)) (set! c (+ c 1))
(set! a (list-tail a 1))
)
这是个好主意如果你的列表总是只有一层深。例如,您要正确检查((a b) c)
和((a) b c)
,但不会得到((a (b)) c)
(具有结构((())())
)和(((a) (b)) c)
(其中包含((()())())
结构a
正确。如果您只是想检查b
和unless
是否具有相同数量的列表元素,(如果eq?
是循环结构) ,你会走在正确的轨道上。
您尝试从每个输入列表中提取表示列表结构(在您的情况下是一个数字)并比较这些代表值的一般方法,这是一个很好的方法。我认为你只需要使用稍微不同的代表值,并稍微区别一点(equal?
对你的情况很好,我想,但我想到的代表值需要{{1} })。
请注意,考虑到它们的定义方式,可以将结构与equal?
进行比较。鉴于这种观察,我认为最简单的方法是编写一个采用列表并返回其规范结构的过程。另请注意,通过在内部list?
中使用if
,我们可以正确处理((a b) ())
等结构为(() ())
的案例。
(define (structure list)
(if (null? list)
list
(if (list? (car list))
(cons (structure (car list)) (structure (cdr list)))
(structure (cdr list)))))
> (structure '(a (b) (c d)))
(() ())
> (structure '((a b) ()))
(() ())
然后,为了比较两个列表的结构,你可以得到两个列表的结构并进行比较。
(define (structure-equal? list1 list2)
(equal? (structure list1)
(structure list2)))
> (structure-equal? '(a b) '(a b c))
#t
> (structure-equal? '(a (b) (c d)) '(a b (c d) (e f g)))
#t
了解equal?
对结构起作用的原因不应该太难,但理解 structure
的工作方式更为重要。让我们更仔细地看一下
(define (structure list)
(if (null? list)
list ; or '()
(if (list? (car list))
(cons (structure (car list)) (structure (cdr list)))
(structure (cdr list)))))
我们假设进来的list
实际上是一个列表。这意味着 空列表()
(因此(null? list)
为真),或者它是具有car
和cdr
的一对。空列表的结构显然是空列表,因此我们可以返回list
(因为它是空的)。另一种情况比较复杂; list
是一对car
具有某种价值且其cdr
是其余列表的一对。如果car
也是一个列表,那么它会向list
的结构添加一些东西,但如果不是,那么它只是一些元素而不会对列表的结构有所贡献。更具体地说,当list
是(x . y)
对时:
x
是列表,则(x . y)
的结构为(<structure of x> . <structure of y>)
x
不是列表,则(x . y)
的结构为<structure of y>
。这应该解释内部if
内部的逻辑(我们使用(a . b)
创建一对(cons a b)
)。