Racket 创建一个修改的'equal?'函数,用于RackUnit

Racket 创建一个修改的'equal?'函数,用于RackUnit,racket,rackunit,Racket,Rackunit,我正在使用check equal?编写一系列测试,对象中包含的语法对象不是eq?。出于这些测试的目的,我可以说两个语法对象是相等的,如果它们在给定给syntax->datum时相等。(是的,我知道这会丢失很多绑定信息,但就目前而言,确保它们的基准相等就足够了。我稍后将测试绑定信息是否良好。) 但是,如果这两个对象不是syntax对象,那么如果它们彼此equal?,我希望它们相等 但是,如果这些对象在某个递归点包含语法对象,我想在它们的基准上测试它们的相等性,所以我不能只做: (define (m

我正在使用
check equal?
编写一系列测试,对象中包含的语法对象不是
eq?
。出于这些测试的目的,我可以说两个语法对象是相等的,如果它们在给定给
syntax->datum
时相等。(是的,我知道这会丢失很多绑定信息,但就目前而言,确保它们的基准相等就足够了。我稍后将测试绑定信息是否良好。)

但是,如果这两个对象不是syntax对象,那么如果它们彼此
equal?
,我希望它们相等

但是,如果这些对象在某个递归点包含语法对象,我想在它们的基准上测试它们的相等性,所以我不能只做:

(define (my-equal? a b)
  (if (and (syntax? a) (syntax? b)
      (equal? (syntax->datum a) (syntax->datum b))
      (equal? a b)))
(define-binary-check (check-my-equal? my-equal? actual expected))
因为这不会进行递归检查

我可以自己处理递归,并且只在原语上使用
equal?
,但这对于实现我自己的相等性测试是至关重要的。

您可以使用它来获得这种行为。此函数的行为类似于
equal?
,但在递归调用的情况下采用不同的函数。因此,您可以像这样实施
my equal?

(define (my-equal? actual expected)
  (if (and (syntax? actual) (syntax? expected))
      (equal? (syntax->datum actual) (syntax->datum expected))
      (equal?/recur actual expected my-equal?)))
但是,请注意,由于您提供的是递归函数,
equal?/recur
不会为您执行任何循环检测。因此,你需要自己去做。一种简单的方法是使用参数:

(define current-equal-visited (make-parameter set))
(define (my-equal? actual expected)
  (cond [(set-member? (current-equal-visited) (cons actual expected))
         #t]
        [(and (syntax? actual) (syntax? expected))
         (equal? (syntax->datum actual) (syntax->datum expected))]
        [else
         (parameterize ([current-equal-visited
                         (set-add (current-equal-visited) (cons actual expected))])
           (equal?/recur actual expected my-equal?))]))
当然,正如您在问题中所注意到的,您可以使用
定义二进制校验
将此过程转换为您可以使用的东西

(define-binary-check (check-my-equal? my-equal? actual expected))