Skip to content

Instantly share code, notes, and snippets.

@jroesch
Last active October 23, 2016 15:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jroesch/4695923 to your computer and use it in GitHub Desktop.
Save jroesch/4695923 to your computer and use it in GitHub Desktop.
A description of how to translate Haskell style typeclasses to Scala.

Given a Haskell Typeclass:

class Point a where 
     distance :: a -> a -> Double

data Point2D = Point2D { x :: Int
                       , y :: Int } deriving (Show, Eq)

instance Point Point2D where
     distance (Point2D x y) (Point2D x' y') = 
         sqrt $ ((x - x') ^^ 2) + ((y - y') ^^ 2) 

In Haskell we declare a Typeclass constraint and use the function as so.

originDistance :: (Point a) => a -> Foo
originDistance x = distance x (Point2D 0 0)

Scala takes a different approach then Haskell and reifies the dictionary(or if you will vtable), a function with a type class in Haskell actually is de-sugared like below, also making the dictionary explicit:

originDistance_d :: PointDict -> a -> Foo
originDistance_d pd x = pd("distance") x (Point2D 0 0)

In the translated version we explicitly pass the dictionary which is used to dynamically lookup the correct implementation to call. You can see the original formualtions in "How to make ad-hoc polymorphism less ad hoc", Wadler & Blott 1989 or "Type Classes in Haskell", Cordelia V. Hall et. al. 1996.

Scala takes that same approach to provide more flexibility in defining and using these constructs, it achieves this using the already existing implicits.

/* declare the *class* of functionality we want, and make it parametric with one type variable A */
trait Point[A] {
  def distance(x: A, y: A): Double
} 

We again define a simple 2DPoint class, similar to the Haskell one. We use an implicit value to build a dictionary, or with an implicit object.

case class CartesianCoord(x: Int, y: Int) 

implicit val cartesianPoint = new Point[CartesianCoord] { 
  def distance(x: CartesianCoord, y: CartesianCoord): Double = 
    Math.sqrt(Math.pow(x.x - y.x, 2) + Math.pow(y.x - y.y, 2))
}

implicit object cartesianPoint extends Point[CartsianCoord] {
  def distance(x: CartesianCoord, y: CartesianCoord): Double = 
    Math.sqrt(Math.pow(x.x - y.x, 2) + Math.pow(y.x - y.y, 2))
}

Implicit's function on type's if you notice both val and object define an entity with type Point[CartesianCoord].

In scala we can use the type class like below:

def originDistance[A : Point](x: A) = {
  val point = implicitly[Point[A]]
  point.distance(x, CartesianCoord(0, 0))
}

def foo[A](x: A)(implicit point: Point[A]) = 
  point.distance(x, CartesianCoord(0, 0))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment