Skip to content

Commit

Permalink
Merge 49e5c54 into 7c9c209
Browse files Browse the repository at this point in the history
  • Loading branch information
stew committed Jan 31, 2016
2 parents 7c9c209 + 49e5c54 commit ece069f
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 0 deletions.
5 changes: 5 additions & 0 deletions core/src/main/scala/cats/Monad.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ import simulacrum.typeclass
@typeclass trait Monad[F[_]] extends FlatMap[F] with Applicative[F] {
override def map[A, B](fa: F[A])(f: A => B): F[B] =
flatMap(fa)(a => pure(f(a)))

/**
* Lift a value of type M[A] into a monad transformer MT[M, A]
*/
def liftM[MT[_[_], _], A](ma: F[A])(implicit MT: MonadTrans[MT]): MT[F, A] = MT.liftM(ma)(this)
}
26 changes: 26 additions & 0 deletions core/src/main/scala/cats/MonadTrans.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cats

/**
* A typeclass which abstracts over monad transformers, providing the
* ability to lift a monad, into the the monad transformer for another
* monad.
*/
trait MonadTrans[MT[_[_], _]] {
/**
* Lift a value of type M[A] into a monad transformer MT[M, A]
*/
def liftM[M[_]: Monad, A](ma: M[A]): MT[M, A]

/**
* Lift a value of type M[A] into a monad transformer MT[M, A] using
* Unapply, this will be useful when the M[A] monad is actually not
* in the * -> * shape. For example Xor[E,A].
*/
def liftMU[MA](ma: MA)(implicit U: Unapply[Monad, MA]): MT[U.M, U.A] = {
liftM[U.M, U.A](U.subst(ma))(U.TC)
}
}

object MonadTrans {
def apply[MT[_[_], _]](implicit MT: MonadTrans[MT]) = MT
}
5 changes: 5 additions & 0 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ private[data] sealed trait OptionTInstances1 {
override def map[A, B](fa: OptionT[F, A])(f: A => B): OptionT[F, B] =
fa.map(f)
}

implicit val optionTMonadTrans: MonadTrans[OptionT] = new MonadTrans[OptionT] {
def liftM[M[_], A](ma: M[A])(implicit M: Monad[M]): OptionT[M, A] =
OptionT(M.map(ma)(Some.apply))
}
}

private[data] sealed trait OptionTInstances extends OptionTInstances1 {
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/cats/data/StreamingT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,12 @@ private[data] sealed trait StreamingTInstances extends StreamingTInstances1 {
def compare(x: StreamingT[F, A], y: StreamingT[F, A]): Int =
x.toList compare y.toList
}

implicit val streamingTMonadTrans: MonadTrans[StreamingT] =
new MonadTrans[StreamingT] {
def liftM[M[_], A](ma: M[A])(implicit M: Monad[M]): StreamingT[M, A] =
StreamingT.single(ma)
}
}

private[data] sealed trait StreamingTInstances1 extends StreamingTInstances2 {
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ private[data] sealed abstract class WriterTInstances extends WriterTInstances0 {
def bimap[A, B, C, D](fab: WriterT[F, A, B])(f: A => C, g: B => D): WriterT[F, C, D] =
fab.bimap(f, g)
}

implicit def writerTMonadTrans[W](implicit W: Monoid[W]): MonadTrans[({type λ[α[_], β]=WriterT[α,W,β]})#λ] =
new MonadTrans[({type λ[α[_], β]=WriterT[α,W,β]})#λ] {
def liftM[M[_], A](ma: M[A])(implicit M: Monad[M]): WriterT[M,W,A] =
WriterT(M.map(ma)((W.empty, _)))
}
}

private[data] sealed abstract class WriterTInstances0 extends WriterTInstances1 {
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/cats/data/XorT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ private[data] abstract class XorTInstances extends XorTInstances1 {
new XorTTraverse[F, L] {
val F0: Traverse[F] = F
}

implicit def xortTMonadTrans[A]: MonadTrans[({type λ[α[_], β] = XorT[α, A, β]})#λ] =
new MonadTrans[({type λ[α[_], β] = XorT[α, A, β]})#λ] {
def liftM[M[_], B](ma: M[B])(implicit M: Monad[M]): XorT[M, A, B] =
XorT(M.map(ma)(Xor.right))
}
}

private[data] abstract class XorTInstances1 extends XorTInstances2 {
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ trait AllSyntax
with GroupSyntax
with InvariantSyntax
with ListSyntax
with MonadSyntax
with MonadCombineSyntax
with MonadFilterSyntax
with OptionSyntax
Expand Down
18 changes: 18 additions & 0 deletions core/src/main/scala/cats/syntax/monad.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cats
package syntax

trait MonadSyntax1 {
implicit def monadSyntaxU[FA](fa: FA)(implicit U: Unapply[Monad, FA]): Monad.Ops[U.M, U.A] =
new Monad.Ops[U.M, U.A] {
val self = U.subst(fa)
val typeClassInstance = U.TC
}
}

trait MonadSyntax extends MonadSyntax1 {
implicit def monadSyntax[F[_], A](fa: F[A])(implicit F: Monad[F]): Monad.Ops[F, A] =
new Monad.Ops[F,A] {
val self = fa
val typeClassInstance = F
}
}
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package object syntax {
object functor extends FunctorSyntax
object group extends GroupSyntax
object invariant extends InvariantSyntax
object monad extends MonadSyntax
object monadCombine extends MonadCombineSyntax
object monadFilter extends MonadFilterSyntax
object option extends OptionSyntax
Expand Down
20 changes: 20 additions & 0 deletions tests/src/test/scala/cats/tests/MonadTransTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cats
package tests

import data.{OptionT,XorT,WriterT,StreamingT}

class MonadTransTests extends CatsSuite {

test("monadTrans syntax on monad works"){

val x: OptionT[List, Int] = List(1).liftM[OptionT]
x.value should === (List(Option(1)))
}

test("we have monadTrans for XorT, OptionT, StreamingT, WriterT"){
val a: WriterT[List, Int, Int] = List(1).liftM[({type λ[α[_], β] = WriterT[α, Int, β]})#λ]
val b: StreamingT[List, Int] = List(1).liftM[StreamingT]
val c: OptionT[List, Int] = List(1).liftM[OptionT]
val d: XorT[List, Int, Int] = List(1).liftM[({type λ[α[_], β] = XorT[α, Int, β]})#λ]
}
}

0 comments on commit ece069f

Please sign in to comment.