What are the key differences between ADTs in F# and Scala? Is there anything that F#'s ADTs can do but Scala's ADTs cannot (and vice versa)?
Conceptually, I think that both languages provide the same power - in F# you can declare ADTs using discriminated unions and in Scala, you can use case classes. The declaration in Scala using classes may get a little bit longer than the F# version (as pointed out by Yin Zhu), but then you can use pattern matching with similar elegancy in both of the languages.
Here is an example (from this article) of simplifying terms:
def simplify(term: Term) = term match {
case Mul(Num(0), x) => Num(0)
case Mul(Num(1), x) => x
case _ => term
}
The same code in F# using match
would look very similar:
let simplify term =
match term with
| Mul(Num(0), x) -> Num(0)
| Mul(Num(1), x) -> x
| _ -> term
Differences I think there are a few differences when it comes to more advanced (related) features.
In Scala, each case is also a type, so you can for example define a method that takes Num
or Mul
as an argument. In F#, this is not possible, because Num
and Mul
are just constructors of type Term
. I suppose this may be sometimes useful, but most of the time, you'll work with values of type Term
anyway.
Related to the previous point - in Scala, you can also define methods for individual cases. You can for example define a method in the Num
class. In F#, all members have to be members of the Term
type.
In F#, you can use active patterns to hide the internal representation of the type (e.g. when exporting it from a module). This is very useful for library design. For example, you can define active patterns:
val (|Mul|_|) // return Some(..) if Term represents multiplication
val (|Num|_|) // return Some(..) if Term represents number
The internal representation can change over time without affecting the library interface, so you can for example implement the interface like this:
type Term = Binary of string * Term * Term | Num of int
let (|Num|_|) = function Num n -> Some n | _ -> None
let (|Mul|_|) = function Binary("*", a, b) -> Some(a, b) | _ -> None
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