In Stanford Scala course I've come across the following assignment:
Exercise 1 – Sets as Functions:
In this exercise we will represent sets as functions from Ints to Booleans:
type Set = Int => Boolean
a) Write a function "set" that takes an Int parameter and returns a Set containing that Int.
b) Write a function "contains" that takes a Set and an Int as parameters and returns true if the Int is in the Set and false otherwise.
c) Write the functions "union", "intersect", and "minus" that take two Sets as parameters and return a Set.
d) Can you write a function "subset" which takes two Sets as parameters and returns true if the first is a subset of the second and false otherwise?
Solutions to the a, b and c are fairly trivial:
def set(i: Int): Set = n => n == i
def contains(s: Set, i: Int) = s(i)
def union(a: Set, b: Set): Set = i => a(i) || b(i)
def intersect(a: Set, b: Set): Set = i => a(i) && b(i)
def minus(a: Set, b: Set): Set = i => a(i) && !b(i)
But is there any elegant solution for d? Of course, strictly speaking, the answer to d is "yes", as I can write something like:
def subset(a: Set, b: Set) = Int.MinValue to Int.MaxValue filter(a) forall(b)
but that's probably not the right way.
We have
Isn't Set A is equivalent to Set B
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():
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)
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:
since
!a(i) || b(i)
is equivalent toa(i) implies b(i)
Here is another version of it using contains function:
I don't think it's possible without iterating through all the integers. For a pseudo-proof, look at the desired type:
Somehow, we've got to produce a
Boolean
when all we have to work with are sets (a
,b
) of typeInt => Boolean
, and integer equality(Int, Int) => Boolean
. From these primitives, the only way to get aBoolean
value is to start withInt
values. Since we don't have any specificInt
'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:
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.