Last active
August 29, 2015 14:14
-
-
Save sshark/48f43ebc926655b78453 to your computer and use it in GitHub Desktop.
Examples of implicit usages
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
| val sampleInts = List(1,2,3,4) | |
| val sampleStrings = List("AA", "BB", "CC") | |
| import annotation.implicitNotFound | |
| @implicitNotFound("Member of type class ${T} not found.") | |
| trait Joinable[T] { | |
| def join(l: List[T]): T | |
| } | |
| implicit object JoinStrings extends Joinable[String] { | |
| override def join(strings: List[String]) = { | |
| println("Joining the strings...") | |
| strings.reduce(_ + _) | |
| } | |
| } | |
| object StringUtils { | |
| implicit object JoinInts extends Joinable[Int] { | |
| override def join(ints: List[Int]) = { | |
| println("Joining the ints...") | |
| ints.foldLeft("")(_.toString + _.toString).toInt | |
| } | |
| } | |
| } | |
| object JoinAll { | |
| def cat(strings: List[String])(implicit ev: Joinable[String]) = ev.join(strings) | |
| def cat(ints: List[Int])(implicit ev: Joinable[Int]) = ev.join(ints) | |
| def cat(symbols: List[Symbol])(implicit ev: Joinable[Symbol]) = ev.join(symbols) | |
| } | |
| // using 'object' to localize imports i.e. StringUtils._ otherwise it will conflicts with | |
| // IntsUtils._ which share the same namespace further down this source file. | |
| object ExampleA { | |
| def run { | |
| println("Running example A...") | |
| import JoinAll._ | |
| import StringUtils._ | |
| println(cat(sampleStrings)) // step A | |
| println(cat(sampleInts)) // step B | |
| // uncomment next line to show custom annotation error message during compilation | |
| // cat(List('a, 'b, 'c)) | |
| } | |
| } | |
| ExampleA.run | |
| // OR better, use type parameter to collapse these functions. 'implicitly' is a function | |
| // defined in Predef. It is a syntactical sugar for the implicit curry form. | |
| object Collasped { | |
| def cat[T:Joinable](strings: List[T]) = implicitly[Joinable[T]].join(strings) | |
| // or use the previous form mentioned above but with type parameter | |
| // def cat[T](strings: List[T])(implicit ev: Joinable[T]) = ev.join(strings) | |
| } | |
| object ExampleB { | |
| def run { | |
| println("Running example B...") | |
| import Collasped._ | |
| import StringUtils._ | |
| println(cat(sampleStrings)) // step C | |
| println(cat(sampleInts)) // step D | |
| } | |
| } | |
| ExampleB.run | |
| // another example with new implicit object | |
| object IntsUtils { | |
| implicit object SumInts extends Joinable[Int] { | |
| override def join(ints: List[Int]) = { | |
| println("Summing the ints...") | |
| ints.reduce(_ + _) | |
| } | |
| } | |
| } | |
| object ExampleC { | |
| def run { | |
| println("Running example C...") | |
| import Collasped._ | |
| import IntsUtils._ | |
| println(cat(sampleInts)) // step C | |
| // compare to the result in step B, it should be 10 instead of "1234" | |
| } | |
| } | |
| ExampleC.run | |
| // pimp my library (add new method to exisitng class) | |
| import java.util.Locale | |
| import java.text.Collator | |
| import scala.language.implicitConversions | |
| trait CanCompare[T] { def compare(a:T, b:T): Boolean } | |
| trait Comparable[T] { def =<(other: T): Boolean } | |
| implicit object SpanishStrings extends CanCompare[String] { | |
| val collator = Collator.getInstance(new Locale("ES")) | |
| def compare(a: String, b: String) = collator.compare(a,b) <= 0 | |
| } | |
| implicit def order[T](a:T)(implicit c: CanCompare[T]) = { | |
| new Comparable[T] { | |
| def =<(b: T) = c.compare(a, b) | |
| } | |
| } | |
| println("aa" =< "bb") | |
| println("ccc" =< "bb") | |
| // functor (for containers) | |
| trait Functor[F[_]] { | |
| def map[X,Y](f: X => Y): F[X] => F[Y] | |
| def get[X](i: Int): F[X] => Option[X] | |
| } | |
| import java.util.ArrayList | |
| import java.util.List | |
| import java.util.Arrays | |
| //implicit object JAL_a_Functor extends Functor[ArrayList] { | |
| implicit object JAL_a_Functor extends Functor[List] { | |
| def map[X,Y](f: X => Y) = (xs: List[X]) => { | |
| val ys = new ArrayList[Y] | |
| for (i <- 0 until xs.size) ys.add(f(xs.get(i))) | |
| ys | |
| } | |
| def get[X](i: Int) = (xs: List[X]) => { | |
| if (i > xs.size - 1) None else Some(xs.get(i)) | |
| } | |
| } | |
| implicit def fops[F[_]: Functor, A](fa: F[A]) = new { | |
| val witness = implicitly[Functor[F]] | |
| final def map[B](f: A => B): F[B] = witness.map(f)(fa) | |
| final def getIt(i: Int): Option[A] = witness.get(i)(fa) | |
| } | |
| //val testList = new ArrayList(Arrays.asList("this", "is", "a", "test")) | |
| val testList = Arrays.asList("this", "is", "a", "test") | |
| val transformed = testList.map(_.toUpperCase) | |
| // have to use method names not found in the current class otherwise implicit won't work | |
| println(transformed) | |
| println(transformed.getIt(2).map(t => s"#${t}").get) | |
| println(transformed.getIt(3).map(t => s"#${t}").get) | |
| println(transformed.getIt(4).map(t => s"#${t}").getOrElse("#EMPTY")) | |
| /* alternately Functor can be written like this, | |
| trait Functor[M[_]] { | |
| def map[A, B](f: A => B, a: M[A]): M[B] | |
| } | |
| implicit object ListFunctor extends Functor[List] { | |
| def map[A, B](f: A => B, a: List[A]): List[B] = a.map(f) | |
| } | |
| def f(l: List[Int])(implicit f: Functor[List]) = f.map((x: Int) => x * 2, l) | |
| def g(l: List[String])(implicit f: Functor[List]) = f.map((x: String) => "@@" + x + "@@", l) | |
| println(f(List(1,2,3))) | |
| println(g(List("a", "b", "c"))) | |
| */ | |
| // another method to handle type erasure from generic container | |
| case class M[A](val i: A) | |
| abstract class Twice { | |
| type Result | |
| def apply(): Result | |
| } | |
| implicit def twiceInt(i: M[Int]) = new Twice { | |
| type Result = Int | |
| override def apply(): Result = i.i * 2 | |
| } | |
| implicit def twiceDouble(i: M[Double]) = new Twice { | |
| type Result = Double | |
| override def apply(): Result = i.i * 2.0 | |
| } | |
| def twice(i: Twice): i.Result = i() | |
| println(twice(M(2.0))) | |
| println(twice(M(2))) |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a complete Scala script where you can run it off command line i.e.
scala pimp-my-libs.scala