创建一个修改过的`equal?`函数,用于RackUnit

时间:2016-05-12 17:29:59

标签: racket rackunit

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

但是,如果这两个对象不是语法对象,我希望它们在相互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?,但这对于实现我自己的相等测试至关重要。

1 个答案:

答案 0 :(得分:1)

您可以使用equal?/recur来解决此问题。此函数的行为类似于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将此过程转换为RackUnit可以使用的内容。

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