I am in the situation below:
import scalaz.Leibniz._
trait Exp[T, C] {
def &&(that: Exp[T, C])(implicit evT: T === Boolean) = LogicalAnd(this, that)
def &&(that: Exp[T, C])(implicit evT: T === Int) = BitwiseAnd(this, that)
}
case class LogicalAnd[C](e1: Exp[Boolean, C], e2: Exp[Boolean, C]) extends Exp[Boolean, C]
case class LogicalOr[C](e1: Exp[Boolean, C], e2: Exp[Boolean, C]) extends Exp[Boolean, C]
...
case class BitwiseAnd[C](e1: Exp[Int, C], e2: Exp[Int, C]) extends Exp[Int, C]
case class BitwiseOr[C](e1: Exp[Int, C], e2: Exp[Int, C]) extends Exp[Int, C]
...
The trait Exp[T,C] is the base trait for and AST for a DSL, I would like to overload built-in scala operators in this trait to allow for infix notation over this dsl, however I would like to constrain some of these methods with a bound on the type T at the trait level so that the same operation here '&&' has a different semantics depending on the type T.
It seems that the leibniz subsitution does not/cannot work here (maybe because it is only defined for functors F[_] with a single argument):
[error] /home/remi/Projects/DSL/src/main/scala/Exp.scala:80: type mismatch;
[error] found : exp.Exp[T,C]
[error] required: exp.Exp[Boolean,?]
[error] = LogicalAnd(this, that)
[error] ^
Does this approach to constraining the trait's T parameter make sense at all ? Is there a way to make leibniz work in this case by "hiding" the second parameter C with something like :
type ExpF[T] = Exp[T, _]
if that even makes sense? Thanks,
Exactly that; define such a type and then use
Leibniz.lift
to, well, lift yourLeibniz
: