Last active
August 29, 2015 14:06
-
-
Save manjuraj/8e8383f90aac3c4e77f3 to your computer and use it in GitHub Desktop.
Typeclass example
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
// | |
// Show typeclass parameterized on a concrete type | |
// | |
trait Show[A] { | |
def show(a: A): String | |
} | |
object Show { | |
implicit object StringShow extends Show[String] { | |
def show(s: String) = s"*$s*" | |
} | |
implicit object IntShow extends Show[Int] { | |
def show(i: Int) = s"~$i~" | |
} | |
implicit def tupleShow[A : Show, B : Show] = new Show[(A, B)] { | |
def show(t: (A, B)) = { | |
val (a, b) = t | |
s"(${a.show}, ${b.show})" | |
} | |
} | |
implicit def setShow[A : Show] = new Show[Set[A]] { | |
def show(xs: Set[A]) = xs.map(_.show).mkString("(", ", ", ")") | |
} | |
implicit def mapShow[K : Show, V : Show] = new Show[Map[K, V]] { | |
def show(m: Map[K, V]) = m.map { case (k, v) => s"${k.show} -> ${v.show}" }.mkString("{", ", ", "}") | |
} | |
implicit class ShowPimps[A](a: A)(implicit ev: Show[A]) { | |
def show = ev.show(a) | |
} | |
// Alternatively, you can use a functional style: | |
// | |
// def show[A](a: A)(implicit ev: Show[A]) = ev.show(a) | |
// or | |
// def show[A : Show](a: A) = implicitly[Show[A]].show(a) | |
// | |
} | |
scala> import Show._ | |
import Show._ | |
scala> Set(1, 2, 3).show | |
res2: String = (~1~, ~2~, ~3~) | |
scala> Map(1 -> 2, 3 -> 4).show | |
res3: String = {~1~ -> ~2~, ~3~ -> ~4~} | |
scala> Map("hello" -> "world").show | |
res5: String = {*hello* -> *world*} | |
scala> Map(1 -> 2, "hello" -> "world").show | |
<console>:23: error: could not find implicit value for parameter ev: Show[scala.collection.immutable.Map[Any,Any]] | |
Map(1 -> 2, "hello" -> "world").show | |
^ | |
<console>:23: error: value show is not a member of scala.collection.immutable.Map[Any,Any] | |
Map(1 -> 2, "hello" -> "world").show | |
^ | |
trait Monoid[A] { | |
def zero: A | |
def op(l: A, r: A): A | |
} | |
// | |
// Foldable typeclass parameterized by a type constructor | |
// | |
trait Foldable[F[_]] { | |
def foldLeft[A, B](fa: F[A], z: => B)(f: (B, A) => B): B | |
def foldMap[A, B](fa: F[A])(f: A => B)(implicit M: Monoid[B]): B | |
} | |
object Foldable { | |
// List is Foldable | |
implicit object ListFoldable extends Foldable[List] { | |
def foldLeft[A, B](xs: List[A], z: => B)(f: (B, A) => B): B = xs.foldLeft(z)(f) | |
def foldMap[A, B](xs: List[A])(f: A => B)(implicit M: Monoid[B]): B = { | |
xs.map(f).foldLeft(M.zero)(M.op) | |
// or, xs.foldLeft(M.zero) { (a, e) => M.op(a, f(e)) } | |
} | |
} | |
implicit def foldableShow[F[_] : Foldable, A : Show] = new Show[F[A]] { | |
import Show._ | |
def show(fa: F[A]): String = fa.foldLeft("") { case (s, a) => s"$s, ${a.show}" } | |
} | |
implicit class FoldablePimps[F[_], A](fa: F[A])(implicit ev: Foldable[F]) { | |
def foldLeft[B](z: => B)(f: (B, A) => B): B = ev.foldLeft(fa, z)(f) | |
} | |
} | |
scala> import Show._, Foldable._ | |
import Show._ | |
import Foldable._ | |
scala> List(1, 2, 3).show | |
res7: String = , ~1~, ~2~, ~3~ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment