你的方法
您的代码(以及您对它的评论)指出了对某些 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)
and((a) b c)
正确,但您不会得到((a (b)) c)
(which has structure ((())())
) and (((a) (b)) c)
(which has structure ((()())())
right。如果您只是想检查和是否a
具有b
与列表相同数量的元素(如果unless
是一个循环结构),你会走在正确的轨道上。
略有不同(但相似)的方法
您尝试从每个输入列表中提取代表列表结构的一些值(在您的情况下为数字)并比较这些代表值时所采用的一般方法是一种很好的方法。我认为您只需要使用稍微不同的代表值,并对它们进行稍微不同的比较(eq?
我认为这对您的情况很好,但我想到的代表值需要equal?
)。
请注意,鉴于它们的定义方式,结构可以与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
and的对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)
。