-
-
Save gvolpe/42a0783fb78a44b2c65bad97c89501d6 to your computer and use it in GitHub Desktop.
Tagless final for ZIO via quantified constraints
This file contains 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
package quantified | |
import cats.Monad | |
import scala.language.implicitConversions | |
/** C[_] constraint applied to type F[_, _] quantified in first parameter */ | |
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