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 one 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
Discrete Structures or some other 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 means that I can't use the
set-subset? function in your submission to
implement set-equals? until I know that
set-subset? is correct! So I need my own
set-subset? function, but I don't want to
overwrite your set-subset? function in the
process.
This wrinkle can be ironed out with a local function...