Last active
August 29, 2015 14:05
-
-
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.
This file contains 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
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") | |
} | |
} |
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
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".