In Stanford Scala course I\'ve come across the following assignment:
Exercise 1 – Sets as Functions:
In this exercise we will represent sets
If there are two sets A and B, then A intersect B is a subset of A and B. Mathematically proven: A ∩ B ⊆ A and A ∩ B ⊆ B
. Function can be written like this:
def filter(s: Set, p: Int => Boolean): Set = x => s(x) && p(x)
Or
def intersect(s: Set, t: Set): Set = x => s(x) && t(x)
def filter(s: Set, p: Int => Boolean): Set = intersect(s,p)
Later on in the Coursera exercises bounded sets are introduced and then forall() and exists() as universal and existential quantifiers over the bounds. subset() was not in the exercises but is similar to forall. Here is my version of subset():
// subset(s,p) tests if p is a subset of p returning true or false
def subset(s: Set, p: Set): Boolean = {
def iter(a: Int): Boolean = {
if (a > bound) { true
} else if (contains(p, a)) {
if (contains(s, a)) iter(a + 1) else false
} else iter(a+1)
}
iter(-bound)
}
We have
Set A =
Returns the intersection of the two given sets,
the set of all elements that are both in `s` and `t`.
Set B =
Returns the subset of `s` for which `p` holds.
Isn't Set A is equivalent to Set B
def filter(s: Set, p: Int => Boolean): Set = intersect(s, p)
I don't think it's possible without iterating through all the integers. For a pseudo-proof, look at the desired type:
def subset: (a: Set, b: Set): Boolean
Somehow, we've got to produce a Boolean
when all we have to work with are sets (a
, b
) of type Int => Boolean
, and integer equality (Int, Int) => Boolean
. From these primitives, the only way to get a Boolean
value is to start with Int
values. Since we don't have any specific Int
's in our hands, the only option is to iterate through all of them.
If we had a magical oracle, isEmpty: Set => Boolean
, the story would be different.
A final option is to encode "false" as the empty set and "true" as anything else, thus changing the desired type to:
def subset: (a: Set, b: Set): Set
With this encoding, logical "or" corresponds to the set union operation, but I don't know that logical "and" or "not" can be defined easily.
I agree with Kipton Barros, you would have to check all values for Ints since you want to prove that forall x, a(x) implies b(x)
.
Regarding the optimization of it, I'd probably write:
def subset(a: Set, b: Set) = Int.MinValue to Int.MaxValue exists(i => !a(i) || b(i))
since !a(i) || b(i)
is equivalent to a(i) implies b(i)
Here is another version of it using contains function:
def union(s: Set, t: Set): Set = x => contains(s,x) || contains(t,x)
def intersect(s: Set, t: Set): Set = x => contains(s,x) && contains(t,x)
def diff(s: Set, t: Set): Set = x => contains(s,x) && !contains(t,x)
def filter(s: Set, p: Int => Boolean): Set = x => contains(s, x) && p(x)