Skip to content

Instantly share code, notes, and snippets.

@pjrt
Last active August 29, 2015 14: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 pjrt/f11273cf0616d7ec1d82 to your computer and use it in GitHub Desktop.
Save pjrt/f11273cf0616d7ec1d82 to your computer and use it in GitHub Desktop.
A Typeclass Box in Scala. Allows for a single type to represent any type that responds to a typeclass.
import language.higherKinds
// Our typeclass with a simple foo :: a -> String func
trait Foo[A] {
def foo(a: A): String
}
object Foo {
implicit def apply[A](implicit ev: Foo[A]) = ev
}
// A Typeclass Box for Foo. It contains an abtract (existential) type A, a value of A and an instance for Foo[A]
trait TBox[C[_]] {
type A
val value: A
val instance: C[A]
}
object TBox {
def apply[C[_], B](value0: B)(implicit ins: C[B]) = new TBox[C] {
type A = B
val value = value0
val instance = ins
}
// A typeclass box can respond to its typeclass (FooBox responds to Foo). Its response is its inner type's response.
implicit val fooBoxFooInstance: Foo[TBox[Foo]] = new Foo[TBox[Foo]] {
def foo(a: TBox[Foo]) = a.instance.foo(a.value)
}
}
// Couple of test objects with their Foo instances
case class MyFoo(a: String)
object MyFoo {
implicit val myFooFooInstance: Foo[MyFoo] = new Foo[MyFoo] {
def foo(a: MyFoo) = a.a
}
}
case class MyBar(a: Int)
object MyBar {
implicit val myBarooInstance: Foo[MyBar] = new Foo[MyBar] {
def foo(a: MyBar) = a.a.toString
}
}
object Main extends App {
override def main(args: Array[String]) {
// Because all FooBox'es have the same type, regardless of their inner type, one can make a list of FooBox'es
val listOfFoo: List[TBox[Foo]] = TBox[Foo, MyFoo](MyFoo("hello")) :: TBox[Foo, MyBar](MyBar(123)) :: Nil
// And map over them and call foo.
println(listOfFoo.map(Foo[TBox[Foo]].foo(_))) // ==>> List("hello", "123")
}
}
@pjrt
Copy link
Author

pjrt commented Apr 23, 2015

Updated to Generalized TBox. Scala's Type Inference is a joke.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment