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 Aug 27, 2014

When compared to this gist, it is interesting to see how little you need to do in Haskell to get the same done. This is mostly due to the fact that type-classes are part of Haskell, as opposed to Scala where they are just a trick that you can do with implicits. Additionally, Scala's syntax is very verbose when compared to Haskell's.

I guess this shows the power and weakness of Scala: it is definitely a scala-ble language that allows you to build things that weren't originally thought of in the language (like type-classes), but at the same time, it is pretty annoying to build these things and the syntax is so ugly. Additionally, it can be misused; there is nothing stopping someone from extending Foo instead of making an instance.

Like that guy in that video said "Slavery is Freedom".

@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