This is done with inheritance in scala (maybe unfortunately as it is more verbose)
sealed trait Expr
case class Val(s: String) extends Expr
case class Integer(i: Int) extends Expr
case class Lower(left: Expr, right: Expr) extends Expr
case class Greater(left: Expr, right: Expr) extends Expr
...
You could type further
sealed trait Expr[A]
case class Val(s: String) extends Expr[String]
case class Integer(i: Int) extends Expr[Int]
case class Lower[X](left: Expr[X], right: Expr[X])(implicit val ordering: Ordering[X]) extends Expr[Boolean]
pattern matching with
def valueOf[A](expr: Expr[A]) : A = expr match {
case Val(s) => s
case Integer(i) => i
case l @ Lower(a,b) => l.ordering.lt(valueOf(a), valueOf(b))
...
}
valueOf would probably be better as a method in Expr
sealed trait Expr[A] {def value: A}
case class Val(value: String) extends Expr[String]
case class Integer(value: Int) extends Expr[Int]
case class Lower[X: Ordering](left: Expr[X], right: Expr[X]) extends Expr[Bool] {
def value = implicitly[Ordering[X]].lt(left.value, right.value)
}
...
Some years later, as this still get some vote now and then.
What is written above still works, but if you use
Scala 3, it has introduced enum which is much more convenient.
The declaration can now be
enum Expr {
case Val(s: String)
case Integer(i: Int)
case Lower(left: Expr, right: Expr)
}
or for the generic version (with GADT)
enum Expr[A] {
case Val(s: String) extends Expr[String]
case Integer(i: Int) extends Expr[Int]
case Lower[X: Ordering](
left: Expr[X],
right: Expr[X]) extends Expr[Boolean]
}
Usage is the same as before, except that the various constructor are not in the top namespace anymore, so you must write e.g Expr.Val
instead of just Val
, both when creating one and when matching (it was actually customary in Scala 2 to write the cases a bit differently of what I had done to avoid having the cases in the top namespace too). However, a simple import Expr._
will make the names directly available again.
Finally, a quite belated answer to @mcintyre321 's comment below: yes there is a warning when the match is not exhaustive.