Last active
August 29, 2015 14:13
-
-
Save eamelink/83ab1192a8adea6e28c8 to your computer and use it in GitHub Desktop.
Capturing type classes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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