Skip to content

Instantly share code, notes, and snippets.

@chenharryhua
Created March 20, 2015 13:45
Show Gist options
  • Save chenharryhua/87a1e89d7ae39ac2b0f8 to your computer and use it in GitHub Desktop.
Save chenharryhua/87a1e89d7ae39ac2b0f8 to your computer and use it in GitHub Desktop.
package futurable
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.language.{ higherKinds, implicitConversions }
import scala.util.Try
import scalaz._
import Scalaz._
object Futurable5 {
trait FutureLike[In] {
type Out
def apply(in: In)(implicit ec: ExecutionContext): Future[Out]
}
case object NoneException extends Exception
trait RebuildException[E <: Throwable] {
def apply(t: Throwable): E
}
object RebuildException {
implicit def noneException = new RebuildException[NoneException.type] {
def apply(t: Throwable) = NoneException
}
implicit def normalException = new RebuildException[Exception] {
def apply(t: Throwable) = new Exception(t.getMessage)
}
}
trait LowPriorityFutureLike {
implicit def futureInstance[T] = new FutureLike[Future[T]] {
type Out = T
def apply(in: Future[T])(implicit ec: ExecutionContext): Future[T] = in
}
implicit def eitherInstance[E <: Throwable, T] =
new FutureLike[\/[E, T]] {
type Out = T
def apply(in: \/[E, T])(implicit ec: ExecutionContext): Future[T] =
in match {
case \/-(x) => Future.successful(x)
case -\/(y) => Future.failed(y)
}
}
implicit def tryInstance[T] = new FutureLike[Try[T]] {
type Out = T
def apply(in: Try[T])(implicit ec: ExecutionContext): Future[T] =
in match {
case util.Success(x) => Future.successful(x)
case util.Failure(y) => Future.failed(y)
}
}
implicit def optionInstance[T] = new FutureLike[Option[T]] {
type Out = T
def apply(in: Option[T])(implicit ec: ExecutionContext): Future[T] =
in match {
case None => Future.failed(NoneException)
case Some(x) => Future.successful(x)
}
}
}
trait FutureLikeRec extends LowPriorityFutureLike {
type FF[X] = Future[Future[X]]
implicit def futureInstanceRec[T](implicit fk: FutureLike[Future[T]]) =
new FutureLike[FF[T]] {
type Out = fk.Out
def apply(in: FF[T])(implicit ec: ExecutionContext): Future[Out] =
in.flatMap { x => fk(x) }
}
type EE[E <: Throwable, X] = \/[E, \/[E, X]]
implicit def eitherInstanceRec[E <: Throwable, T](
implicit fk: FutureLike[\/[E, T]]) =
new FutureLike[EE[E, T]] {
type Out = fk.Out
def apply(in: EE[E, T])(implicit ec: ExecutionContext): Future[Out] = {
val cont = in.fold(a => -\/(a), identity)
fk(cont)
}
}
type TT[X] = Try[Try[X]]
implicit def tryInstanceRec[T](implicit fk: FutureLike[Try[T]]) =
new FutureLike[TT[T]] {
type Out = fk.Out
def apply(in: TT[T])(implicit ec: ExecutionContext): Future[Out] =
fk(for { tt <- in; t <- tt } yield t)
}
type OO[X] = Option[Option[X]]
implicit def optionInstanceRec[T](implicit fk: FutureLike[Option[T]]) =
new FutureLike[OO[T]] {
type Out = fk.Out
def apply(in: OO[T])(implicit ec: ExecutionContext): Future[Out] =
fk(for { oo <- in; o <- oo } yield o)
}
}
trait OptionFutureIso extends FutureLikeRec {
type FO[X] = Future[Option[X]]
implicit def foInstance[T](implicit fk: FutureLike[Option[T]]) =
new FutureLike[FO[T]] {
type Out = fk.Out
def apply(in: FO[T])(implicit ec: ExecutionContext): Future[Out] =
in.flatMap { x => fk(x) }
}
type OF[X] = Option[Future[X]]
implicit def ofInstance[T](implicit fk: FutureLike[Future[T]]) =
new FutureLike[OF[T]] {
type Out = fk.Out
def apply(in: OF[T])(implicit ec: ExecutionContext): Future[Out] = {
val f0: Future[T] = in match {
case Some(x) => x
case None => Future.failed(NoneException)
}
fk(f0)
}
}
}
trait TryFutureIso extends FutureLikeRec {
type FT[X] = Future[Try[X]]
implicit def ftIntance[T](implicit fk: FutureLike[Try[T]]) =
new FutureLike[FT[T]] {
type Out = fk.Out
def apply(in: FT[T])(implicit ec: ExecutionContext): Future[Out] =
in.flatMap { x => fk(x) }
}
type TF[X] = Try[Future[X]]
implicit def tfInstance[T](implicit fk: FutureLike[Future[T]]) =
new FutureLike[TF[T]] {
type Out = fk.Out
def apply(in: TF[T])(implicit ec: ExecutionContext): Future[Out] = {
val f0: Future[Future[T]] = in match {
case util.Success(x) => Future.successful(x)
case util.Failure(y) => Future.failed(y)
}
f0.flatMap { x => fk(x) }
}
}
}
trait EitherFutureIso extends FutureLikeRec {
type FE[E <: Throwable, X] = Future[\/[E, X]]
implicit def feIntance[E <: Throwable, T](implicit fk: FutureLike[\/[E, T]]) =
new FutureLike[FE[E, T]] {
type Out = fk.Out
def apply(in: FE[E, T])(implicit ec: ExecutionContext): Future[Out] =
in.flatMap { x => fk(x) }
}
type EF[E <: Throwable, X] = \/[E, Future[X]]
implicit def efInstance[E <: Throwable, T](implicit fk: FutureLike[Future[T]]) =
new FutureLike[EF[E, T]] {
type Out = fk.Out
def apply(in: EF[E, T])(implicit ec: ExecutionContext): Future[Out] = {
val f0: Future[Future[T]] = in match {
case \/-(x) => Future.successful(x)
case -\/(y) => Future.failed(y)
}
f0.flatMap { x => fk(x) }
}
}
}
trait TryEitherIso extends FutureLikeRec {
type ET[E <: Throwable, X] = \/[E, Try[X]]
implicit def etIntance[E <: Throwable, T](implicit fk: FutureLike[Try[T]]) =
new FutureLike[ET[E, T]] {
type Out = fk.Out
def apply(in: ET[E, T])(implicit ec: ExecutionContext): Future[Out] =
in match {
case \/-(x) => fk(x)
case -\/(y) => fk(util.Failure(y))
}
}
type TE[E <: Throwable, X] = Try[\/[E, X]]
implicit def teInstance[E <: Throwable, T](
implicit fk: FutureLike[\/[E, T]], re: RebuildException[E]) =
new FutureLike[TE[E, T]] {
type Out = fk.Out
def apply(in: TE[E, T])(implicit ec: ExecutionContext): Future[Out] =
in match {
case util.Success(x) => fk(x)
case util.Failure(y) => fk(-\/(re(y)))
}
}
}
trait TryOptionIso extends FutureLikeRec {
type OT[X] = Option[Try[X]]
implicit def otIntance[T](implicit fk: FutureLike[Try[T]]) =
new FutureLike[OT[T]] {
type Out = fk.Out
def apply(in: OT[T])(implicit ec: ExecutionContext): Future[Out] =
in match {
case None => fk(util.Failure(NoneException))
case Some(x) => fk(x)
}
}
type TO[X] = Try[Option[X]]
implicit def toInstance[T](implicit fk: FutureLike[Option[T]]) =
new FutureLike[TO[T]] {
type Out = fk.Out
def apply(in: TO[T])(implicit ec: ExecutionContext): Future[Out] =
in match {
case util.Success(x) => fk(x)
case util.Failure(y) => fk(None)
}
}
}
trait EitherOptionIso extends FutureLikeRec {
type OE[E <: Throwable, X] = Option[\/[E, X]]
implicit def oeIntance[E <: Throwable, T](
implicit fk: FutureLike[\/[E, T]], re: RebuildException[E]) =
new FutureLike[OE[E, T]] {
type Out = fk.Out
def apply(in: OE[E, T])(implicit ec: ExecutionContext): Future[Out] =
in match {
case None => fk(-\/(re(NoneException)))
case Some(x) => fk(x)
}
}
type EO[E <: Throwable, X] = \/[E, Option[X]]
implicit def eoInstance[E <: Throwable, T](implicit fk: FutureLike[Option[T]]) =
new FutureLike[EO[E, T]] {
type Out = fk.Out
def apply(in: EO[E, T])(implicit ec: ExecutionContext): Future[Out] =
in match {
case \/-(x) => fk(x)
case -\/(y) => fk(None)
}
}
}
object FutureLike extends FutureLikeRec
with OptionFutureIso
with EitherFutureIso
with TryFutureIso
with TryEitherIso
with TryOptionIso
with EitherOptionIso {
implicit def eitherTransformer[F[_], E <: Throwable, T](implicit fk: FutureLike[F[\/[E, T]]]) =
new FutureLike[EitherT[F, E, T]] {
type Out = fk.Out
def apply(in: EitherT[F, E, T])(implicit ec: ExecutionContext): Future[Out] = fk(in.run)
}
implicit def optionTransformer[F[_], T](implicit fk: FutureLike[F[Option[T]]]) =
new FutureLike[OptionT[F, T]] {
type Out = fk.Out
def apply(in: OptionT[F, T])(implicit ec: ExecutionContext): Future[Out] = fk(in.run)
}
}
object FuturableSyntax {
implicit class FSyntax[F, O](a: F)(implicit val f: FutureLike[F] { type Out = O }) {
def toFuture(implicit ec: ExecutionContext) = f(a)
}
}
object MyTest {
import FuturableSyntax._
import scala.concurrent.ExecutionContext.Implicits.global
val ooo: Option[Option[Option[Int]]] = ???
val oooi: Future[Int] = ooo.toFuture
val fff: Future[Future[Future[Int]]] = ???
val fffi: Future[Int] = fff.toFuture
val eee: \/[Exception, \/[Exception, \/[Exception, Int]]] = ???
// val eeei: Future[Int] = eee.toFuture
val ttt: Try[Try[Try[Int]]] = ???
val ttti: Future[Int] = ttt.toFuture
val ggg = ttt.toFuture
val e: \/[Exception, Int] = ???
val en = e.toFuture
val ofoofooof: Option[Future[Option[Option[Future[Option[Option[Option[Future[Int]]]]]]]]] = ???
val ofoofooofi: Future[Int] = ofoofooof.toFuture
val ofoofooofn = ofoofooof.toFuture
val tfttftttf: Try[Future[Try[Try[Future[Try[Try[Try[Future[Int]]]]]]]]] = ???
val tfttftttfi: Future[Int] = tfttftttf.toFuture
val efeef: \/[Exception, Future[\/[Exception, \/[Exception, Future[Int]]]]] = ???
val efeefi: Future[Int] = efeef.toFuture
val etet: \/[Exception, Try[\/[Exception, Try[Int]]]] = ???
val eteti: Future[Int] = etet.toFuture
val ftf: Future[Try[Future[Int]]] = ???
val ftfi: Future[Int] = ftf.toFuture
val otf: Option[Try[Future[Int]]] = ???
val otfi: Future[Int] = otf.toFuture
val ot: Option[Try[Int]] = ???
val oti: Future[Int] = ot.toFuture
val to: Try[Option[Int]] = ???
val toi: Future[Int] = to.toFuture
val otootfooettf: Option[Try[Option[Option[Try[Future[Option[Option[Option[\/[Exception, Try[Try[Future[Int]]]]]]]]]]]]] = ???
val otootfooottfi: Future[Int] = otootfooettf.toFuture
val etfo: Option[\/[Exception, Try[Future[Option[\/[Exception, Future[Try[Int]]]]]]]] = ???
val etfoi: Future[Int] = etfo.toFuture
val et: EitherT[Future, Exception, Int] = ???
val etf: Future[Int] = et.toFuture
val fEto: EitherT[Option, Exception, Int] = ???
val fEtof = fEto.toFuture
val oT: OptionT[Future, Int] = ???
val oTf = oT.toFuture
type E[X] = \/[Exception, X]
val a: OptionT[E, Int] = ???
val aa = a.toFuture
val b: OptionT[Try, Int] = ???
val bb = b.toFuture
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment