How would one go about transforming an Discriminated Union in F# to Scala:
type Expr = | Val of String | Integer of Int32 | Lower of Expr * Expr | Greater of Expr * Expr | And of Expr * Expr | Or of Expr * Expr
There is a similar post talking about ADTs in F# and Scala, but that doesn't seem to be what I am after.
Discriminated unions are useful for heterogeneous data; data that can have special cases, including valid and error cases; data that varies in type from one instance to another; and as an alternative for small object hierarchies. In addition, recursive discriminated unions are used to represent tree data structures.
In F#, a sum type is called a “discriminated union” type. Each component type (called a union case) must be tagged with a label (called a case identifier or tag) so that they can be told apart (“discriminated”). The labels can be any identifier you like, but must start with an uppercase letter.
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[A], right: Expr[A]) extends Expr[Bool] { def value = implicitly[Ordering[X]].lt(left.value, right.value) } ...
I totally agree with Didier Dupont, but if you need higher level of abstraction, implementation of the option type in Scala gives a good intuition:
sealed trait Option[+E] case class Some[+E]( element : E ) extends Option[E] case object None extends Option[Nothing]
Source: https://mauricio.github.io/2013/12/25/learning-scala-by-building-scala-lists-part-3.html
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