Skip to content

Instantly share code, notes, and snippets.

@frgomes
Last active December 5, 2018 23:38
Show Gist options
  • Save frgomes/21670dfdb294809452bdc5b790cdef06 to your computer and use it in GitHub Desktop.
Save frgomes/21670dfdb294809452bdc5b790cdef06 to your computer and use it in GitHub Desktop.
scala - convenience implicit conversions for optional types
package rgomes.info.lang
import utest._
object OptionalSyntaxSpec extends TestSuite {
trait OptionalWrapper[T] {
def wrap(data: T): Option[T]
}
object OptionalInstances {
import scala.language.implicitConversions
import scala.language.higherKinds
implicit object StringConverter extends OptionalWrapper[String] { implicit def wrap(a: String) : Option[String] = Option(a) }
implicit object IntConverter extends OptionalWrapper[Int] { implicit def wrap(a: Int) : Option[Int] = Option(a) }
implicit object LongConverter extends OptionalWrapper[Long] { implicit def wrap(a: Long) : Option[Long] = Option(a) }
implicit object FloatConverter extends OptionalWrapper[Float] { implicit def wrap(a: Float) : Option[Float] = Option(a) }
implicit object DoubleConverter extends OptionalWrapper[Double] { implicit def wrap(a: Double) : Option[Double] = Option(a) }
implicit object BooleanConverter extends OptionalWrapper[Boolean] { implicit def wrap(a: Boolean): Option[Boolean] = Option(a) }
/* This one is more elaborated: OptionWrapper[Seq[A]] needs OptionWrapper[A], which can be found implicitly. */
implicit def SeqWrapper[A](implicit itemWrapper: OptionalWrapper[A]): OptionalWrapper[Seq[A]] = new OptionalWrapper[Seq[A]] {
def wrap(a: Seq[A]): Option[Seq[A]] = Option(a)
}
/* This one is more elaborated: OptionWrapper[List[A]] needs OptionWrapper[A], which can be found implicitly. */
implicit def ListWrapper[A](implicit itemWrapper: OptionalWrapper[A]): OptionalWrapper[List[A]] = new OptionalWrapper[List[A]] {
def wrap(a: List[A]): Option[List[A]] = Option(a)
}
}
trait OptionalSyntax {
import scala.language.implicitConversions
implicit def wrap[A](a: A)(implicit o: OptionalWrapper[A]): Option[A] = o.wrap(a)
}
val tests = this {
"Ability to wrap a String" - {
object CallSite extends OptionalSyntax {
import OptionalInstances._
val s: Option[String] = "this is a String"
}
assert(CallSite.s == Some("this is a String"))
}
...
"Ability to wrap List[A]" - {
object CallSite extends OptionalSyntax {
import OptionalInstances._
val xs: Option[List[String]] = List("a", "b", "c")
val xi: Option[List[Int]] = List(1, 2, 3)
val xl: Option[List[Long]] = List(1L, 2L, 3L)
val xf: Option[List[Float]] = List(1.0f, 2.0f, 3.0f)
val xd: Option[List[Double]] = List(1.0, 2.0, 3.0)
val xb: Option[List[Boolean]] = List(true, false, true)
}
assert(CallSite.xs == Some(List("a", "b", "c")))
assert(CallSite.xi == Some(List(1, 2, 3)))
assert(CallSite.xl == Some(List(1L, 2L, 3L)))
assert(CallSite.xf == Some(List(1.0f, 2.0f, 3.0f)))
assert(CallSite.xd == Some(List(1.0, 2.0, 3.0)))
assert(CallSite.xb == Some(List(true, false, true)))
}
}
}
@frgomes
Copy link
Author

frgomes commented Dec 5, 2018

This is an example of how a typeclass can be implemented.

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