Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More flexible TransLift #940

Merged
merged 6 commits into from
Apr 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions core/src/main/scala/cats/TransLift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,24 @@ package cats
* A typeclass which abstracts over the ability to lift an M[A] into a
* MonadTransformer
*/
trait TransLift[MT[_[_], _], M[_]] {
trait TransLift[MT[_[_], _]] {

/**
* The typeclass which constrains liftT as a function of the type
* constructor it is given. A safe "identity" value for this type
* if your transformer does not constrain its lifted effects would
* be `type TC[M[_]] = Trivial`. A more common constraint might be
* `type TC[M[_]] = Monad[M]`.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this doc comment need to be updated to refer to Trivial?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Will fix.

type TC[M[_]]

/**
* Lift a value of type M[A] into a monad transformer MT[M, A]
*/
def liftT[A](ma: M[A]): MT[M,A]
def liftT[M[_]: TC, A](ma: M[A]): MT[M, A]
}

object TransLift {
type Aux[MT[_[_], _], TC0[_[_]]] = TransLift[MT] { type TC[M[_]] = TC0[M] }
type AuxId[MT[_[_], _]] = Aux[MT, Trivial.PH1]
}
23 changes: 23 additions & 0 deletions core/src/main/scala/cats/Trivial.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package cats

/**
* The "Unit typeclass". The only instance of `Trivial` is given by
* `Trivial.manifest`, and this instance is guaranteed to be in the
* implicit scope. Several convenience type aliases are provided in
* companion object, covering a few common use cases and avoiding the
* need for unnecessary lambdas (e.g. if you want a trivial typeclass
* instance for a type constructor, you should use `Trivial.PH1`).
*/
sealed trait Trivial

object Trivial {
type P1[A] = Trivial
type PH1[F[_]] = Trivial
type P1H1[F[_], A] = Trivial
type P2[A, B] = Trivial
type P2H1[F[_], A, B] = Trivial
type P3[A, B, C] = Trivial
type P3H1[F[_], A, B, C] = Trivial

implicit val manifest: Trivial = new Trivial {}
}
10 changes: 6 additions & 4 deletions core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,11 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {
fa.local(f)
}

implicit def kleisliTransLift[M[_], A]: TransLift[({type λ[α[_], β] = Kleisli[α, A, β]})#λ, M] =
new TransLift[({type λ[α[_], β] = Kleisli[α, A, β]})#λ, M] {
def liftT[B](ma: M[B]): Kleisli[M, A, B] = Kleisli[M, A, B](a => ma)
implicit def kleisliTransLift[A]: TransLift.AuxId[Kleisli[?[_], A, ?]] =
new TransLift[Kleisli[?[_], A, ?]] {
type TC[M[_]] = Trivial

def liftT[M[_], B](ma: M[B])(implicit ev: Trivial): Kleisli[M, A, B] = Kleisli[M, A, B](a => ma)
}
}

Expand Down Expand Up @@ -244,7 +246,7 @@ private trait KleisliStrong[F[_]] extends Strong[Kleisli[F, ?, ?]] {
private trait KleisliSemigroup[F[_], A, B] extends Semigroup[Kleisli[F, A, B]] {
implicit def FB: Semigroup[F[B]]

override def combine(a: Kleisli[F, A, B], b: Kleisli[F, A, B]): Kleisli[F, A, B] =
override def combine(a: Kleisli[F, A, B], b: Kleisli[F, A, B]): Kleisli[F, A, B] =
Kleisli[F, A, B](x => FB.combine(a.run(x), b.run(x)))
}

Expand Down
9 changes: 6 additions & 3 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,12 @@ private[data] sealed trait OptionTInstances1 {
fa.map(f)
}

implicit def optionTTransLift[M[_]: Functor]: TransLift[OptionT, M] =
new TransLift[OptionT, M] {
def liftT[A](ma: M[A]): OptionT[M, A] = OptionT.liftF(ma)
// do NOT change this to val! I know it looks like it should work, and really I agree, but it doesn't (for... reasons)
implicit def optionTTransLift: TransLift.Aux[OptionT, Functor] =
new TransLift[OptionT] {
type TC[M[_]] = Functor[M]

def liftT[M[_]: Functor, A](ma: M[A]): OptionT[M, A] = OptionT.liftF(ma)
}
}

Expand Down
8 changes: 5 additions & 3 deletions core/src/main/scala/cats/data/StateT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,11 @@ private[data] sealed abstract class StateTInstances {
fa.map(f)
}

implicit def stateTLift[M[_], S](implicit M: Applicative[M]): TransLift[({type λ[α[_], β] = StateT[α, S, β]})#λ, M] =
new TransLift[({type λ[α[_], β] = StateT[α, S, β]})#λ, M] {
def liftT[A](ma: M[A]): StateT[M, S, A] = StateT(s => M.map(ma)(s -> _))
implicit def stateTLift[S]: TransLift.Aux[StateT[?[_], S, ?], Applicative] =
new TransLift[StateT[?[_], S, ?]] {
type TC[M[_]] = Applicative[M]

def liftT[M[_]: Applicative, A](ma: M[A]): StateT[M, S, A] = StateT(s => Applicative[M].map(ma)(s -> _))
}

}
Expand Down
10 changes: 6 additions & 4 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ private[data] sealed abstract class WriterTInstances extends WriterTInstances0 {
fab.bimap(f, g)
}

implicit def writerTTransLift[M[_], W](implicit M: Functor[M], W: Monoid[W]): TransLift[({type λ[α[_], β] = WriterT[α,W,β]})#λ, M] =
new TransLift[({type λ[α[_], β] = WriterT[α,W,β]})#λ, M] {
def liftT[A](ma: M[A]): WriterT[M, W, A] =
WriterT(M.map(ma)((W.empty, _)))
implicit def writerTTransLift[W](implicit W: Monoid[W]): TransLift.Aux[WriterT[?[_], W, ?], Functor] =
new TransLift[WriterT[?[_], W, ?]] {
type TC[M[_]] = Functor[M]

def liftT[M[_]: Functor, A](ma: M[A]): WriterT[M, W, A] =
WriterT(Functor[M].map(ma)((W.empty, _)))
}

implicit def writerTShow[F[_], L, V](implicit F: Show[F[(L, V)]]): Show[WriterT[F, L, V]] = new Show[WriterT[F, L, V]] {
Expand Down
10 changes: 6 additions & 4 deletions core/src/main/scala/cats/data/XorT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,12 @@ private[data] abstract class XorTInstances extends XorTInstances1 {
val F0: Traverse[F] = F
}

implicit def xortTransLift[M[_],E](implicit M: Functor[M]): TransLift[({type λ[α[_], β] = XorT[α,E,β]})#λ, M] =
new TransLift[({type λ[α[_], β] = XorT[α,E,β]})#λ, M] {
def liftT[A](ma: M[A]): XorT[M,E,A] =
XorT(M.map(ma)(Xor.right))
implicit def xortTransLift[E]: TransLift.Aux[XorT[?[_], E, ?], Functor] =
new TransLift[XorT[?[_], E, ?]] {
type TC[M[_]] = Functor[M]

def liftT[M[_]: Functor, A](ma: M[A]): XorT[M,E,A] =
XorT(Functor[M].map(ma)(Xor.right))
}

}
Expand Down
31 changes: 28 additions & 3 deletions core/src/main/scala/cats/syntax/transLift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,34 @@ package cats
package syntax

trait TransLiftSyntax {
implicit def transLiftSyntax[M[_], A](ma: M[A]): TransLiftOps[M, A] = new TransLiftOps(ma)
implicit def transLiftSyntax[E](ma: E)(implicit U: Unapply[Trivial.PH1, E]): TransLiftOps[U.M, U.A] = new TransLiftOps(U.subst(ma))
}

final class TransLiftOps[M[_], A](val ma: M[A]) extends AnyVal {
def liftT[MT[_[_],_]](implicit TL: TransLift[MT, M]): MT[M,A] = TL.liftT(ma)
final class TransLiftOps[M0[_], A](val ma: M0[A]) extends AnyVal {
import TLExtract._

def liftT[MT0[_[_],_]](implicit extract: TLExtract[SingletonMT { type MT[F[_], B] = MT0[F, B] }, SingletonM { type M[B] = M0[B] }]): MT0[M0, A] = extract.TL.liftT(ma)(extract.TC)
}

trait TLExtract[MTS <: TLExtract.SingletonMT, MS <: TLExtract.SingletonM] {
val TL: TransLift[MTS#MT]
val TC: TL.TC[MS#M]
}

object TLExtract {

trait SingletonMT {
type MT[F[_], A]
}

trait SingletonM {
type M[A]
}

implicit def extract[MTS <: SingletonMT, MS <: SingletonM, TC[_[_]]](implicit TL0: TransLift.Aux[MTS#MT, TC], TC0: TC[MS#M]): TLExtract[MTS, MS] = new TLExtract[MTS, MS] {
val TL = TL0
val TC = TC0
}

implicit def extractId[MTS <: SingletonMT, MS <: SingletonM](implicit TL0: TransLift.Aux[MTS#MT, Trivial.PH1]): TLExtract[MTS, MS] = extract[MTS, MS, Trivial.PH1]
}