I am defining few ADTs representing logic formulas. They all use i.e. And
constructor, but then differ in what other constructors they use. I'd like to reuse case class definitions with a hope that I could reuse some code later. I'd like to do something like:
sealed trait Formula
selaed trait PositiveFormula
case class Not(sub) extends Formula
case class And(left, right) extends Formula, PositiveFormula
but this doesn't work for any single type for sub
, left
and right
.
So I'd like to say:
sealed trait Formula
selaed trait PositiveFormula
case class Not[A](sub : A)
Not[Formula] extends Formula
case class And(left : A, right : A)
And[Formula] extends Formula
And[PositiveFormula] extends PositiveFormula
few questions:
- Is anything like above possible and I just dont know syntax?
- Is there other solution to "reuse case class constructors" problem?
- Whats your opinion on how useful this would be if possible?
CodePudding user response:
You need types for case class fields. You can probably make PositiveFormula
extend Formula
too. For example, this would work for Boolean
operands.
sealed trait Formula
sealed trait PositiveFormula extends Formula
case class Not(sub:Boolean) extends Formula
case class And(left:Boolean, right:Boolean) extends PositiveFormula
CodePudding user response:
In Scala parametric classes can't extend different parents for different type parameters (only parent's type parameter can vary).
It seems you want to have something like "Not[T] extends T
", "And[T] extends T
" (pseudocode). See Scala : class[T] extends T?
You can try
sealed trait Formula
sealed trait PositiveFormula
trait NotLike[A] {
def sub: A
// your generic code here
}
case class Not(sub: Formula) extends NotLike[Formula] with Formula
trait AndLike[A] {
def left: A
def right: A
// your generic code here
}
case class And(left: Formula, right: Formula) extends
AndLike[Formula] with Formula
case class PositiveAnd(left: PositiveFormula, right: PositiveFormula) extends
AndLike[PositiveFormula] with PositiveFormula
You can also introduce FormulaLike
, a common parent for Formula
and PositiveFormula
sealed trait FormulaLike
sealed trait Formula extends FormulaLike
sealed trait PositiveFormula extends FormulaLike
trait NotLike[A <: FormulaLike] {
def sub: A
}
trait AndLike[A <: FormulaLike] {
def left: A
def right: A
}
Is PositiveFormula
a Formula
or not? Just in case, if so then you can make PositiveFormula
extend Formula
(instead of introducing FormulaLike
).
Or maybe you can try to express your relations between types with type classes (inheritance can be too restrictive, composition should be preferred over inheritance)
https://www.baeldung.com/scala/type-classes
https://kubuszok.com/2018/implicits-type-classes-and-extension-methods-part-1/
https://tpolecat.github.io/2015/04/29/f-bounds.html
https://github.com/milessabin/shapeless/blob/main/core/shared/src/main/scala/shapeless/ops/nat.scala
// hierarchy
sealed trait Formula
// type class
trait IsPositive[A <: Formula]
case class Not[A <: Formula](sub: A) extends Formula
case class And[A <: Formula](left: A, right: A) extends Formula
implicit def and[A <: Formula](implicit ev: IsPositive[A]): IsPositive[And[A]] = null