Skip to content

Commit

Permalink
First stab at a more flexible TransLift
Browse files Browse the repository at this point in the history
  • Loading branch information
djspiewak committed Mar 5, 2016
1 parent b638e29 commit 8dfb9fd
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 21 deletions.
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[_]] = Unit =:= Unit`. A more common constraint
* might be `type TC[M[_]] = Monad[M]`.
*/
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, λ[X[_] => Unit =:= Unit]] // TODO we need a Trivial typeclass
}
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[_]] = Unit =:= Unit

def liftT[M[_], B](ma: M[B])(implicit ev: Unit =:= Unit): 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 @@ -129,9 +129,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 @@ -63,10 +63,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, _)))
}
}

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 @@ -194,10 +194,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
21 changes: 20 additions & 1 deletion core/src/main/scala/cats/syntax/transLift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,24 @@ trait TransLiftSyntax {
}

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)
def liftT[MT[_[_],_]](implicit extract: TLExtract[MT, M]): MT[M, A] = extract.TL.liftT(ma)(extract.TC)
}

trait TLExtract[MT[_[_], _], M[_]] {
val TL: TransLift[MT]
val TC: TL.TC[M]
}

object TLExtract {

implicit def extract1[MT[_[_], _], M[_], TC[_[_]]](implicit TL0: TransLift.Aux[MT, TC], TC0: TC[M]): TLExtract[MT, M] = new TLExtract[MT, M] {
val TL = TL0
val TC = TC0
}

implicit def extract1Id[MT[_[_], _], M[_]](implicit TL0: TransLift.Aux[MT, λ[X[_] => Unit =:= Unit]], TC0: Unit =:= Unit): TLExtract[MT, M] = extract1[MT, M, λ[X[_] => Unit =:= Unit]]

// sigh...
implicit def extract2[MT[_[_], _, _], Z, M[_], TC[_[_]]](implicit TL0: TransLift.Aux[MT[?[_], Z, ?], TC], TC0: TC[M]): TLExtract[MT[?[_], Z, ?], M] = extract1[MT[?[_], Z, ?], M, TC]
implicit def extract2Id[MT[_[_], _, _], Z, M[_]](implicit TL0: TransLift.Aux[MT[?[_], Z, ?], λ[X[_] => Unit =:= Unit]], TC0: Unit =:= Unit): TLExtract[MT[?[_], Z, ?], M] = extract1[MT[?[_], Z, ?], M, λ[X[_] => Unit =:= Unit]]
}

0 comments on commit 8dfb9fd

Please sign in to comment.