Skip to content

Instantly share code, notes, and snippets.

@nodemvc
Last active April 4, 2017 17:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nodemvc/6735a8bf0699256d199db7ac9cad0dbb to your computer and use it in GitHub Desktop.
Save nodemvc/6735a8bf0699256d199db7ac9cad0dbb to your computer and use it in GitHub Desktop.

How Tagged Types are implemented in Scalaz

This gist explains how Tagged Types are implemented in ScalaZ. Hope this helps someone.

Snippets taken from Tim Perret's blog on tagged types in Scalaz 7.

First, let's take a look at the type definition:

type @@[T, Tag] = T with Tagged[Tag]
type Tagged[T] = {type Tag = T}

Substituting the type alias Tagged[Tag] with its actual type gives you:

type @@[T, Tag] = T with { type Tag = T }

The RHS value T with { type Tag = T } might look a little peculiar. Scala supports structural types and that's exactly what { type Tag = T } is. Check out this example from the Twitter scala course on Types:

scala> def foo(x: { def get: Int }) = 123 + x.get
foo: (x: AnyRef{def get: Int})Int

scala> foo(new { def get = 10 })
res0: Int = 133

In the example above, you can pass in any type as long as the type has a method get that returns an Int.

Going back to our original discussion, for the type alias

type @@[T, Tag] = T with { type Tag = T }

it's saying @@[T, Tag] is a type alias for a type T that mixes in the structural type { type Tag = T }.

Now, let's take a look at a more concrete example:

  sealed trait Points
  trait PaintPoints extends Points
  trait ThreePointers extends Points

  def PointsInsideThePaint[A](a: A): A @@ PaintPoints =
    Tag[A, PaintPoints](a)

  def PointsBehindTheArc[A](a: A): A @@ ThreePointers =
    Tag[A, ThreePointers](a)

  def getAveragePaintPoints(a: Int @@ PaintPoints, games: Int): Double =
    Tag.unwrap(a).toDouble / games.toDouble

  val paintPoints = PointsInsideThePaint(12)
  val threePointers = PointsBehindTheArc(33)

  // works, types align. paintPoints is @@[Int, PaintPoints] which is whwat getAveragePaintPoints expects
  getAveragePaintPoints(paintPoints, 1)

  // wouldn't work - expects @@[Int, PaintPoints], not @@[Int, ThreePointers]
  getAveragePaintPoints(threePointers, 3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment