Skip to content

Instantly share code, notes, and snippets.

@eamelink
Last active August 29, 2015 14:13
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 eamelink/83ab1192a8adea6e28c8 to your computer and use it in GitHub Desktop.
Save eamelink/83ab1192a8adea6e28c8 to your computer and use it in GitHub Desktop.
Capturing type classes
object MyApp extends App {
// The type class we use in all examples
trait Show[A] {
def show(a: A): String
}
implicit val StringShow = new Show[String] { def show(a: String) = "String(" + a + ")" }
implicit val IntShow = new Show[Int] { def show(a: Int) = "Int(" + a.toString + ")" }
// Problem description
object problem {
// Strings and Ints both have 'Show' instances.
// We want to have a collection of things-with-a-Show-instance,
// and, somewhere else, show these things.
val showableThings = List("foo", 77)
showableThings.foreach { v =>
// ??? How do we show this? `v` is now of type Any, and we can't show that.
}
}
// method1: Existential type
object method1 {
type Showable = (A, Show[A]) forSome { type A }
val list = List[Showable]("foo" -> StringShow, 77 -> IntShow)
// Prints:
// String(Foo)
// Int(77)
list.foreach {
case (a, showA) =>
println(showA.show(a))
}
}
// Method2: Type member on a non-parameterized trait
object method2 {
trait Showable {
type T
val elem: T
val Show: Show[T]
}
object Showable {
def apply[U](e: U)(implicit s: Show[U]): Showable = new Showable {
type T = U
override val elem = e
override val Show = s
}
}
val list = List[Showable](Showable("foo"), Showable(77))
// Prints:
// String(Foo)
// Int(77)
list.foreach { S =>
println(S.Show.show(S.elem))
}
}
// Method3: Method 2 generalized, and implicit capturing
object method3 {
trait Captured[A[_]] {
type T
val value: T
implicit val tc: A[T]
}
object Captured {
implicit def apply[A[_], U](e: U)(implicit c1: A[U]) = new Captured[A] {
type T = U
val value = e
val tc = c1
}
}
import Captured._
val list = List[Captured[Show]]("Foo", 77)
list.foreach { C =>
C.tc.show(C.value)
}
}
// Method4: implicit capturing to an existential tuple type
object method4 {
type Captured[T[_]] = (A, T[A]) forSome { type A }
implicit def Capture[A: T, T[_]](value: A): Captured[T] = value -> implicitly[T[A]]
val list = List[Captured[Show]]("Foo", 77)
list.foreach { case ((value, show)) =>
println(show.show(value))
}
}
// Method5: capturing multiple type classes
object method5 {
// Here we have an additional type class 'Shout', and we want to capture both 'Show' and 'Shout'
trait Shout[A] {
def shout(a: A): String
}
implicit val StringShout = new Shout[String] { def shout(a: String) = a + "!!!" }
implicit val IntShout = new Shout[Int] { def shout(a: Int) = a.toString + "!!!" }
type Captured[T[_]] = (A, T[A]) forSome { type A }
type Captured2[T[_], U[_]] = (A, T[A], U[A]) forSome { type A }
type Captured3[T[_], U[_], V[_]] = (A, T[A], U[A], V[A]) forSome { type A }
type Captured4[T[_], U[_], V[_], W[_]] = (A, T[A], U[A], V[A], W[A]) forSome { type A }
type Captured5[T[_], U[_], V[_], W[_], X[_]] = (A, T[A], U[A], V[A], W[A], X[A]) forSome { type A }
implicit def Capture[A: T, T[_]](value: A): Captured[T] = (value, implicitly[T[A]])
implicit def Capture[A: T: U, T[_], U[_]](value: A): Captured2[T, U] = (value, implicitly[T[A]], implicitly[U[A]])
implicit def Capture[A: T: U: V, T[_], U[_], V[_]](value: A): Captured3[T, U, V] = (value, implicitly[T[A]], implicitly[U[A]], implicitly[V[A]])
implicit def Capture[A: T: U: V: W, T[_], U[_], V[_], W[_]](value: A): Captured4[T, U, V, W] = (value, implicitly[T[A]], implicitly[U[A]], implicitly[V[A]], implicitly[W[A]])
implicit def Capture[A: T: U: V: W: X, T[_], U[_], V[_], W[_], X[_]](value: A): Captured5[T, U, V, W, X] = (value, implicitly[T[A]], implicitly[U[A]], implicitly[V[A]], implicitly[W[A]], implicitly[X[A]])
val list = List[Captured2[Show, Shout]]("Foo", 77)
// Prints:
// String(Foo) - Foo!!!
// Int(77) - 77!!!
list.foreach { case ((value, show, shout)) =>
println(show.show(value) + " - " + shout.shout(value))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment