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 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...