Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a modified `equal?` function for use with RackUnit

I am writing a bunch of tests using check-equal? with objects that contain syntax objects that are not eq?. For the purposes of these tests, I am okay with saying that two syntax objects are equal if they're equal when given to syntax->datum. (Yes, I know that looses a lot of binding information, but for now, ensuring their datums are equal is good enough. I will test that the binding information is good later.)

If the two objects are not syntax objects, however, I want them to be equal if they are equal? to each other.

However, if those objects contain syntax objects in them at some recursive point, I want to test their equality on their datums, so I can't just do:

(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))

Because this will not do the recursive check.

I could handle the recursion myself, and only use equal? on primitives, but that would be paramount to implementing my own equality testing.

like image 879
Leif Andersen Avatar asked Feb 15 '26 11:02

Leif Andersen


1 Answers

You can use equal?/recur to get this behavior. This function behaves like equal?, but takes a different function in the case of a recursive call. So you could potentially implement my-equal? like this:

(define (my-equal? actual expected)
  (if (and (syntax? actual) (syntax? expected))
      (equal? (syntax->datum actual) (syntax->datum expected))
      (equal?/recur actual expected my-equal?)))

However, note that because you are providing the recursive function, equal?/recur does not do any cycle detection for you. As such, you need to do it yourself. One easy way to do this is with parameters:

(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?))]))

And then, of course, as you noticed in your question, you can use define-binary-check to turn this procedure into something RackUnit can you.

(define-binary-check (check-my-equal? my-equal? actual expected))
like image 95
Leif Andersen Avatar answered Feb 18 '26 01:02

Leif Andersen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!