Testing Set Operations
When Order Doesn't Matter...
As some of you have noticed, testing the functions you write for
Problem 3
and
Problem 4
on Homework 7 creates a new problem for us: The functions
set-add
and set-union
returns sets, which
are lists. But the items in a set can be in any order, so
check-equal?
is too restrictive.
(check-equal? (set-union '(a b) '(x y z)) '(a b x y z))
The two lists do not have to be equal; they only need to contain the same items as each other.
Rackunit provides a higher-order check operator that allows us to pass our own test predicate:
(check set-equals? (set-union '(a b) '(x y z)) '(a b x y z))
Now all we need is a function set-equals?
that takes
two sets as arguments and returns true if they contain the same
items as each other, and false otherwise:
> (set-equals? '(a b x y z) '(z y x a b)) #t > (set-equals? '(a b x y z) '(a b w y x)) #f
How would you write a recursive (set-equal? S1 S2)
function?
We might try to use the same structurally recursive approach that
we use for (set-union S1 S2)
and
(set-subset? S1 S2)
on the homework. The challenge
is to find a way to process on of the sets item by item.
(If you are up for the challenge, give it a try.)
However, once you've written set-subset?
, we have a
shortcut. You may remember this definition from another course:
two sets S1 and S2 are equal to one another if and only if
S1 ⊂ S2 and
S2 ⊂ S1. So:
(define set-equals? (lambda (S1 S2) (and (set-subset? S1 S2) (set-subset? S2 S1))))
This enables us to write tests using Rackunit's check operator as above. And that's what I'll do when I evaluate your Homework 7 solutions.
My set-equals?
is not quite that simple, though. I am
testing student code, which creates several wrinkles for me. One
is this: I can't use the set-subset?
function in your
submission to implement set-equals?
until I know that
set-subset?
is correct! This wrinkle can be ironed
out with a local function...