Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ADT subtyping in Scala

Is there an equivalent to the OO notion of subtyping for the ADT pattern as used in Scala? In particular I would like to add methods to more specialized types. For example, given a generic List ADT:

sealed trait List[+A]
case class Cons[+A](h: A, t: List[A]) extends List[A]
case object Nil[Nothing]

I'd like to define new methods for lists of particular types:

sealed trait List[+A]
sealed trait DuckList extends List[Duck] {
    def feed(l: DuckList) = ...
}

but then I'd also have to define special data constructors (DuckCons, DuckNil) for these new types, and since case classes don't support (case-to-case) inheritance, there is no way to relate a DuckCons to the generic Cons such that it would work in pattern matching, so the generic methods defined for List wouldn't work for DuckList.

like image 895
estolua Avatar asked Nov 05 '13 02:11

estolua


People also ask

What is ADT in Scala?

Algebraic Data Types (ADTs for short) are a way of structuring data. They're widely used in Scala due, mostly, to how well they work with pattern matching and how easy it is to use them to make illegal states impossible to represent. There are two basic categories of ADTs: product types. sum types.

Does Scala have sum types?

Sum Type. The sum type in Scala is implemented by way of inheritance. The values of the sum type can are subtypes associated with logical disjunctions (ORs), where the possible values are this subtype OR that subtype … Here we create a sum type from Option that can either be None , or a Some containing a tuple.


1 Answers

Use the type class pattern.

For one example, consider how Ordering is implemented. It adds a method -- compare -- to a set of closed classes, but it does so not by adding the method directly but, instead, providing an instance that has such a method for that particular class. Ordering[Int], to continue with the example, is implemented like this:

trait IntOrdering extends Ordering[Int] {
  def compare(x: Int, y: Int) =
    if (x < y) -1
    else if (x == y) 0
    else 1
}
implicit object Int extends IntOrdering

That is, the object Ordering.Int (for this is inside the object Ordering) implements a method compare that takes two Int as a parameter. This object is provided implicitly, so that the user does not need to pass it explicitly. List's sorted method takes advantage of this:

def sorted[B >: A](implicit ord: math.Ordering[B]): List[A]

Then it can call ord.compare on instances of the list to order them. I encourage you to look at Ordering to understand what it is doing.

like image 84
Daniel C. Sobral Avatar answered Sep 24 '22 23:09

Daniel C. Sobral