I have defined some top level objects in a simply hierarchy because I want their apply
methods to always behave the same way in several base cases. Because of the apply
methods defined in BinaryOperation
I can call any of the objects And
, Or
, Xor
etc as if they were functions, and I can pass exactly two arguments, either of which is a positive integer and either of which is a Bdd
. Thus I can evaluate an expression such as Or(And(1,2),And(3,Xor(2,4)))
. The integers are treated as Boolean variables such as x1, x2, x3, x4. The result of this evaluation is an object which represents the Boolean function (x1 and x2) or (x3 and (x2 xor x4))
.
This works great, but I’m limited to only use binary functions. I’d like to have varargs semantics. I’d like to say And(Or(1,2),Or(2,3),Or(1,3),Or(3,4))
, but I’d also like to use And(1,2,3,Or(4,5,And(1,2)),Xor(2,5))
.
I can’t figure out how to have a varargs function which accepts arguments which are each either Integer
or Bdd
. Can this be done somehow simply with varargs apply
in the BinaryOperation
class whose implementation is a call to fold
? My guess is the answer is sadly “No” because Scala does not support union types. I can declare a parameter as Integer | Bdd
.
If that supposition is correct, then can I do it with an implicit conversion? I.e., can I have the apply method implicitly convert any Integer n
to a Bdd
by calling the constructor Bdd(n)
, thus also eliminating the need for the 4 apply
methods in the BinaryOperator
class? And also eliminating the need to implement the Boolean operators as objects, allowing them to be implemented as regular functions?
sealed abstract class BinaryOperation() {
def apply(b1: Bdd, b2: Bdd): Bdd
def apply(l1: Int, l2: Int): Bdd = {
this (Bdd(l1), Bdd(l2))
}
def apply(l1: Int, b2: Bdd): Bdd = {
this (Bdd(l1), b2)
}
def apply(b1: Bdd, l2: Int): Bdd = {
this (b1, Bdd(l2))
}
}
object And extends BinaryOperation {
def apply(b1: Bdd, b2: Bdd): Bdd = {
(b1, b2) match {
case (b1, b2) if (b1 eq b2) => b1
case (BddTrue, _) => b2
case (BddFalse, _) => BddFalse
case (_, BddTrue) => b1
case (_, BddFalse) => BddFalse
case (b1: BddNode, b2: BddNode) => Bdd.bddOp(this, b1, b2)
}
}
}
object Or extends BinaryOperation {
def apply(b1:Bdd,b2:Bdd):Bdd = {
...
}
}
object Xor extends BinaryOperation {
def apply(b1:Bdd,b2:Bdd):Bdd = {
...
}
}
object Xnor extends BinaryOperation {
def apply(b1:Bdd,b2:Bdd):Bdd = {
...
}
}
object AndNot extends BinaryOperation {
def apply(b1:Bdd,b2:Bdd):Bdd = {
...
}
}