From the question linked here, I found this implementation of Union in Scala:
def union(a: Set, b: Set): Set = i => a(i) || b(i)
And Set is a function of type:
type Set = Int => Boolean
Now I understand that in Scala, a function is mapped from Int to Boolean here, and I further understand how this statement is executed:
a(i) || b(i)
But what I don't understand is what is 'i' here. Where does it come from? And when it finds a match between to sets, it returns true, if it indeed does, where do I filter it?
As the name suggests, a Union Type denotes a type that is the union of two or more types. For example, we can define a union type of Int and String values and use it as a parameter of a function that expects either an integer or string value as input. Scala is a strongly and statically typed language.
The intersect() method is utilized to compute the intersection between two sets. Return Type: It returns a set containing the elements present in both the sets.
++= can mean two different things in Scala: 1: Invoke the ++= method. In your example with flatMap , the ++= method of Builder takes another collection and adds its elements into the builder. Many of the other mutable collections in the Scala collections library define a similiar ++= method.
There are two kinds of Sets, the immutable and the mutable. The difference between mutable and immutable objects is that when an object is immutable, the object itself can't be changed. By default, Scala uses the immutable Set.
The Set
(which is just a function) that gets returned from union
takes some integer as a parameter; you must give it an arbitrary name so that you can refer to it in the function body. It may make more sense if you write the function like this:
def union(a: Set, b: Set): Set = {
(i) => a(i) || b(i)
}
It may make even more sense if you write it like this:
def union(a: Set, b: Set): Set = {
// The union of two sets is a new function that takes an Int...
def theUnion(i: Int): Boolean = {
// and returns true if EITEHR of the other functions are true
a(i) || b(i)
}
// Now we want to return the NEW function
theUnion
}
Again, i
is arbitrary and could be replaced with any variable:
def union(a: Set, b: Set): Set = item => a(item) || b(item)
[Update]
Because we're representing sets as functions, there's no need to iterate to see if they contain a number. For example, here's a set that contains any number below -5
:
val belowNegFive: Set = (i) => i < -5
When we call that function with a number, it will tell us if that number is in the set. Note that at no time did we actually tell it the specific numbers that were in the set:
scala> belowNegFive(10)
res0: Boolean = false
scala> belowNegFive(-100)
res1: Boolean = true
scala> belowNegFive(-1)
res2: Boolean = false
Here's another set that includes any number between 50
and 100
:
val fiftyToHundred: Set = (i) => i >= 50 && i <= 100
scala> fiftyToHundred(50)
res3: Boolean = true
scala> fiftyToHundred(100)
res4: Boolean = true
scala> fiftyToHundred(75)
res5: Boolean = true
scala> fiftyToHundred(49)
res6: Boolean = false
Now, a union of the sets belowNegFive
and fiftyToHundred
would contain any number that is either below -5
or between 50
and 100
. We can easily represent this in code by returning a new function which itself returns true if either of the other two functions returns true.
scala> val unionOfBoth: Set = (i) => belowNegFive(i) || fiftyToHundred(i)
unionOfBoth: Int => Boolean = <function1>
scala> unionOfBoth(-10)
res7: Boolean = true
scala> unionOfBoth(50)
res8: Boolean = true
scala> unionOfBoth(0)
res9: Boolean = false
The union
function from your question is just a way of applying this pattern generically over any two sets.
Let say we have object called SoSet
given by
object SoSet {
type Set = Int => Boolean
val a : Set = ???
val b : Set = ???
def isItem(item : Int) = a(item) || b(item)
}
The signature of isItem
is given by Int => Boolean
which is a Set
. So far so good.
But now we just want to return the function isItem
(i.e. a Set
).
So lets define union
function for this (There are no parameters right now. We will add it later).
object SoSet {
//..
def union : Set = isItem // returns the function isItem
}
Now lets refactor the isItem
into a anonymous function.
object SoSet {
//..
def union : Set = {
(item : Int) => a(item) || b(item)
}
}
Lets move Set a and b
from object SoSet
to parameters of def union
. Refactor item
to i
.
object SoSet {
type Set = Int => Boolean
def union(a : Set, b : Set) : Set = (i : Int) => a(i) || b(i)
}
UPDATE
val s1 = Set(1, 2, 3)
val s2 = Set(2, 3, 4)
val s3 = union(s1, s2) // returns the function.. Int => Boolean = <function1>
s3(2) // invokes the function & checks if 2 is present in the union
And when it finds a match between to sets, it returns true, if it indeed does, where do I filter it?
union
does not find a match between two sets, it creates a new set which contains the values of
both sets. Example:
val a = (i) => i == 2 // a contains 2 as a(2) == True
val b = (i) => i == 5 // b contains 5 as b(5) == True
val u = union(a, b) // u contains 2 and 5 as u(2) == True and u(5) == True
So the 'filtering' just happens on the way. This function is not iterating over each set, filtering specific things out, it just returns a combination of two functions which then can executed later to query for the actual values.
Example of querying the values of a union:
val a = (i) => i == 2
val b = (i) => i == 5
val u = union(a, b)
for(i <- 1 to 10 if u(i)) yield i // returns Vector(2, 5)
And yes, this is not an optimal way of storing values in sets as you have to check values by guessing but it is a good way to demonstrate how combining functions adds complex functionality without writing very complex code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With