如何检查两个S表达式在Scheme中是否在结构上相同?

时间:2015-10-13 21:32:31

标签: scheme racket

我不完全确定如何处理这个问题。我想我想通过辅助函数分别通过x和y,并让辅助函数根据它找到的函数返回一个值,然后比较它们(结构上?x y)。但是,我可以想到使用这种方法的多种方法可能会出错。

define (structurally? x y) 
(
...
)

示例:

(structurally? quote(1 2 (3 a 5) (b 6 c "string" 7 (5)) 9)      
               quote(2 1 (3 "string" 5) (b 6 c a 7 (5)) 9))

结果是#t

 (structurally? '(1 2 (3 a b 5) (b 6 c "string" 7 (5)) 9)
                '(2 1 (3 "string" 5) (b 6 c d a 7 (5)) 9))

结果是#f

3 个答案:

答案 0 :(得分:1)

为此,我们必须同时遍历两个列表列表,特别注意边缘情况。如果我们设法遍历列表而没有其中一个在另一个之前结束,那么我们可以说它们在结构上相等。试试这个:

(define (structurally? exp1 exp2)
        ; if we reach the end of both lists, they're equal
  (cond ((and (null? exp1) (null? exp2)) #t)
        ; if we reach the end of one before the other, they're distinct
        ((and (null? exp1) (not (null? exp2))) #f)
        ; if we reach the end of one before the other, they're distinct
        ((and (not (null? exp1)) (null? exp2)) #f)
        ; if we find an atom they're equal, no matter its value
        ((not (pair? exp1)) #t)
        ; recursive step: advance over `car` and `cdr` of both lists
        ; simultaneously, combining all partial results using `and`
        (else
         (and (structurally? (car exp1) (car exp2))
              (structurally? (cdr exp1) (cdr exp2))))))

按预期工作:

(structurally? '(1 2 (3 a 5) (b 6 c "string" 7 (5)) 9)
               '(2 1 (3 "string" 5) (b 6 c a 7 (5)) 9))
=> #t

(structurally? '(1 2 (3 a b 5) (b 6 c "string" 7 (5)) 9)
               '(2 1 (3 "string" 5) (b 6 c d a 7 (5)) 9))
=> #f

答案 1 :(得分:1)

ÓscarLópez的解决方案可以通过这种方式简化:

(define (structurally? exp1 exp2)
     (cond ((not (pair? exp1)) (not (pair? exp2)))
           ((not (pair? exp2)) #f)
           (else (and (structurally? (car exp1) (car exp2))
                      (structurally? (cdr exp1) (cdr exp2))))))

cond的第一个分支中,我们说如果第一个表达式不是一对,那么函数的结果就是检查第二个表达式是否也不是一对。这也是递归的最后一种情况之一,因为你不能重复使用非配对值。

在第二个分支中,我们知道exp1是一对,所以如果exp2不是一对,则表达式在结构上不等同。这是递归的另一个最后一例。

最后,递归情况等于另一种解决方案。

答案 2 :(得分:0)

我想我明白为什么你给出的例子是真的和假的,但我不确定结果表达式树的样子。假设您有表达式e,例如数学表达式(+ (+ 2 4) 5)。根+(car e),左侧树(+ 2 4)(cadr e),右侧树5(caddr e)。在结构上,该表达式与(+ (- 3 7) 1)相同,但评估结果不同......

如果您浏览表达式并且没有c(a)drc(a)ddr,那么您已经到达了该方向的遍历结束。

你可能需要一个辅助方法,但我想象(and (equal? (car x) (car y)) (structurally? (cdr x) (cdr y)) (structurally? (cddr x) (cddr y)))的效果会让你开始。