Skip to content

Instantly share code, notes, and snippets.

@neko-kai
Last active April 2, 2019 13:53
Show Gist options
  • Save neko-kai/e070d96e3b3b10a6f200542714585639 to your computer and use it in GitHub Desktop.
Save neko-kai/e070d96e3b3b10a6f200542714585639 to your computer and use it in GitHub Desktop.
Tagless final for ZIO via quantified constraints
package quantified
import cats.Monad
import scala.language.implicitConversions
/**
* C[_] constraint applied to type F[_, _] quantified in first parameter, i.e.
*
* {{{
* forall E. C[F[E, ?]]
* }}}
*
* Usage:
*
* {{{
* import quantified._
* import cats.syntax.all._
*
* def poly[F[_, _]: Monad2] = abc[F].flatMap(cba[F]) *> 123.pure[F[Nothing, ?]]
* }}}
*
* With covariance:
*
* {{{
* import quantified._
* import quantified.Monad2._
* import cats.syntax.all._
*
* def nothing[F[+ _, +_] : Monad2]: F[Nothing, Unit] = ().pure[F[Nothing, ?]]
* def throwable[F[+ _, +_] : Monad2]: F[Throwable, Unit] = nothing
* def runtime[F[+ _, +_] : Monad2]: F[RuntimeException, Unit] = nothing
* def test[F[+_, +_]: Monad2]: F[Throwable, Int] =
* for {
* x <- 2.pure[F[Nothing, ?]]
* _ <- nothing
* _ <- runtime
* _ <- throwable
* y <- 7.pure[F[Nothing, ?]]
* } yield x + y
* }}}
*
* */
final class Quant[+C[_[_]], F[_, _]] private (private val erased: C[F[Any, ?]]) extends AnyVal {
type State = Defined
@inline def underlying[E]: C[F[E, ?]] = erased.asInstanceOf[C[F[E, ?]]]
}
object Quant extends QuantImplicits {
@inline final def apply[C[_[_]], F[_, _]](implicit q: Quant[C, F]): Quant[C, F] = q
final def apply[C[_[_]]]: QuantApply[C] = new QuantApply[C]()
private[Quant] final class QuantApply[C[_[_]]](private val dummy: Boolean = false) extends AnyVal {
def apply[F[_, _], E](c: C[F[E, ?]]): Quant[C, F] = new Quant[C, F](c.asInstanceOf[C[F[Any, ?]]])
}
private sealed trait Private {
private[Quant] type T
}
private[Quant] final val Private = new Private {}
/** If somehow there's an instance that's valid for a fresh private type T >: Nothing <: Any,
it means that this instance must be a polymorphic instance valid for all type parameters X >: Nothing <: Any **/
implicit def fromImplicitDef[C[_[_]], F[_, _]](implicit lp: shapeless.LowPriority, c: C[F[Private.T, ?]]): Quant[C, F] { type State = Derived } =
Quant[C].apply(c.asInstanceOf[C[F[Any, ?]]]).asInstanceOf[Quant[C, F] { type State = Derived }]
}
trait QuantImplicits extends Any {
final type Monad2[F[_, _]] = Quant[Monad, F]
object Monad2 {
final def apply[F[_, _]: Monad2]: Monad2[F] = implicitly[Quant.Monad2[F]]
implicit final class Monad2CovariantFlatMap[F[+_, _], E, A](self: F[E, A])(implicit ev: Monad2[F] { type State = Defined }) {
@inline def flatMap[E1 >: E, B](f: A => F[E1, B]): F[E1, B] =
apply[F].apply[E1].flatMap(self)(f)
@inline def *>[E1 >: E, B](f: => F[E1, B]): F[E1, B] =
flatMap[E1, B](_ => f)
}
}
@inline implicit final def instantiate[C[_[_]], F[_, _], E](implicit lp: shapeless.LowPriority, q: Quant[C, F] { type State = Defined }): C[F[E, ?]] = q.underlying
// Also works via Param:
// @inline implicit final def instantiate[C[_[_]], F[_, _], E](implicit lp: shapeless.LowPriority, c: Param[Lambda[E => C[F[E, ?]]]] { type State = Defined }): C[F[E, ?]] = c.underlying
@inline implicit final def conversion[C[_[_]], F[_, _], E](q: Quant[C, F]): C[F[E, ?]] = q.underlying
}
private[quantified] trait Defined
private[quantified] trait Derived
/** Universally quantified instance for C */
final class Param[C[_]](private val erased: C[_]) {
type State = Defined
def underlying[A]: C[A] = erased.asInstanceOf[C[A]]
}
object Param extends ParamImplicits {
def apply[C[_]: Param]: Param[C] = implicitly
private sealed trait Private {
private[Param] trait T extends Any
}
private[Param] final val Private = new Private {}
/** If there's somehow an instance for a fresh private type >: Nothing <: Any,
it means that this instance is a polymorphic instance valid for all type parameters >: Nothing <: Any **/
implicit def fromImplicitDef[C[_]](implicit lp: shapeless.LowPriority, c: C[Private.T]): Param[C] { type State = Derived } =
new Param(c).asInstanceOf[Param[C] { type State = Derived }]
}
trait ParamImplicits {
@inline implicit final def instantiate[C[_], A](implicit lp: shapeless.LowPriority, c: Param[C] { type State = Defined }): C[A] = c.underlying
@inline implicit final def conversion[C[_], A](c: Param[C]): C[A] = c.underlying
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment