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

standardise on liftF and add liftK to transformers #2033

Merged
merged 10 commits into from
Nov 27, 2017
9 changes: 7 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,16 @@ def mimaSettings(moduleName: String) = Seq(
exclude[ReversedMissingMethodProblem]("cats.instances.ParallelInstances.catsStdNonEmptyParallelForZipList"),
exclude[ReversedMissingMethodProblem]("cats.instances.ParallelInstances.catsStdParallelForFailFastFuture"),
exclude[DirectMissingMethodProblem]("cats.data.EitherTInstances2.catsDataMonadErrorForEitherT"),
exclude[DirectMissingMethodProblem]("cats.data.EitherTInstances2.catsDataMonadErrorForEitherT"),
exclude[ReversedMissingMethodProblem]("cats.Foldable.collectFirstSome"),
exclude[ReversedMissingMethodProblem]("cats.Foldable.collectFirst"),
exclude[ReversedMissingMethodProblem]("cats.Foldable#Ops.collectFirstSome"),
exclude[ReversedMissingMethodProblem]("cats.Foldable#Ops.collectFirst")
exclude[ReversedMissingMethodProblem]("cats.Foldable#Ops.collectFirst"),
exclude[ReversedMissingMethodProblem]("cats.data.CommonIRWSTConstructors.liftF"),
exclude[ReversedMissingMethodProblem]("cats.data.CommonIRWSTConstructors.liftK"),
exclude[ReversedMissingMethodProblem]("cats.data.KleisliFunctions.liftF"),
exclude[ReversedMissingMethodProblem]("cats.data.KleisliFunctions.liftK"),
exclude[ReversedMissingMethodProblem]("cats.data.CommonStateTConstructors.liftF"),
exclude[ReversedMissingMethodProblem]("cats.data.CommonStateTConstructors.liftK")
)
}
)
Expand Down
13 changes: 13 additions & 0 deletions core/src/main/scala/cats/data/EitherT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,19 @@ object EitherT extends EitherTInstances {
*/
final def liftF[F[_], A, B](fb: F[B])(implicit F: Functor[F]): EitherT[F, A, B] = right(fb)

/**
* Same as [[liftF]], but expressed as a FunctionK for use with mapK
* {{{
* scala> import cats._, data._, implicits._
* scala> val a: OptionT[Eval, Int] = 1.pure[OptionT[Eval, ?]]
* scala> val b: OptionT[EitherT[Eval, String, ?], Int] = a.mapK(EitherT.liftK)
* scala> b.value.value.value
* res0: Either[String,Option[Int]] = Right(Some(1))
* }}}
*/
final def liftK[F[_], A](implicit F: Functor[F]): F ~> EitherT[F, A, ?] =
λ[F ~> EitherT[F, A, ?]](right(_))

@deprecated("Use EitherT.liftF.", "1.0.0-RC1")
final def liftT[F[_], A, B](fb: F[B])(implicit F: Functor[F]): EitherT[F, A, B] = right(fb)

Expand Down
21 changes: 19 additions & 2 deletions core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,23 @@ private[data] sealed trait CommonIRWSTConstructors {
/**
* Return an effectful `a` and an empty log without modifying the input state.
*/
def liftF[F[_], E, L, S, A](fa: F[A])(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, A] =
IndexedReaderWriterStateT((_, s) => F.map(fa)((L.empty, s, _)))

/**
* Same as [[liftF]], but expressed as a FunctionK for use with mapK
* {{{
* scala> import cats._, data._, implicits._
* scala> val a: OptionT[Eval, Int] = 1.pure[OptionT[Eval, ?]]
* scala> val b: OptionT[RWST[Eval, Boolean, List[String], String, ?], Int] = a.mapK(RWST.liftK)
* scala> b.value.runEmpty(true).value
* res0: (List[String], String, Option[Int]) = (List(),"",Some(1))
* }}}
*/
def liftK[F[_], E, L, S](implicit F: Applicative[F], L: Monoid[L]): F ~> IndexedReaderWriterStateT[F, E, L, S, S, ?] =
λ[F ~> IndexedReaderWriterStateT[F, E, L, S, S, ?]](IndexedReaderWriterStateT.liftF(_))

@deprecated("Use liftF instead", "1.0.0")
def lift[F[_], E, L, S, A](fa: F[A])(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, A] =
IndexedReaderWriterStateT((_, s) => F.map(fa)((L.empty, s, _)))

Expand Down Expand Up @@ -570,7 +587,7 @@ private[data] sealed abstract class RWSTAlternative[F[_], E, L, S]
G.combineK(x.run(e, sa), y.run(e, sa))
}

def empty[A]: ReaderWriterStateT[F, E, L, S, A] = ReaderWriterStateT.lift(G.empty[A])
def empty[A]: ReaderWriterStateT[F, E, L, S, A] = ReaderWriterStateT.liftF(G.empty[A])

def pure[A](a: A): ReaderWriterStateT[F, E, L, S, A] = ReaderWriterStateT.pure[F, E, L, S, A](a)

Expand All @@ -584,7 +601,7 @@ private[data] sealed abstract class RWSTMonadError[F[_], E, L, S, R]

implicit def F: MonadError[F, R]

def raiseError[A](r: R): ReaderWriterStateT[F, E, L, S, A] = ReaderWriterStateT.lift(F.raiseError(r))
def raiseError[A](r: R): ReaderWriterStateT[F, E, L, S, A] = ReaderWriterStateT.liftF(F.raiseError(r))

def handleErrorWith[A](fa: ReaderWriterStateT[F, E, L, S, A])(f: R => ReaderWriterStateT[F, E, L, S, A]): ReaderWriterStateT[F, E, L, S, A] =
ReaderWriterStateT { (e, s) =>
Expand Down
21 changes: 19 additions & 2 deletions core/src/main/scala/cats/data/IndexedStateT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,23 @@ private[data] trait CommonStateTConstructors {
def pure[F[_], S, A](a: A)(implicit F: Applicative[F]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.pure((s, a)))

def liftF[F[_], S, A](fa: F[A])(implicit F: Applicative[F]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.map(fa)(a => (s, a)))

/**
* Same as [[liftF]], but expressed as a FunctionK for use with mapK
* {{{
* scala> import cats._, data._, implicits._
* scala> val a: OptionT[Eval, Int] = 1.pure[OptionT[Eval, ?]]
* scala> val b: OptionT[StateT[Eval, String, ?], Int] = a.mapK(StateT.liftK)
* scala> b.value.runEmpty.value
* res0: (String, Option[Int]) = ("",Some(1))
* }}}
*/
def liftK[F[_], S](implicit F: Applicative[F]): F ~> IndexedStateT[F, S, S, ?] =
λ[F ~> IndexedStateT[F, S, S, ?]](IndexedStateT.liftF(_))

@deprecated("Use liftF instead", "1.0.0")
def lift[F[_], S, A](fa: F[A])(implicit F: Applicative[F]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.map(fa)(a => (s, a)))

Expand Down Expand Up @@ -369,14 +386,14 @@ private[data] sealed abstract class IndexedStateTAlternative[F[_], S] extends In
IndexedStateT[F, S, S, A](s => G.combineK(x.run(s), y.run(s)))(G)

def empty[A]: IndexedStateT[F, S, S, A] =
IndexedStateT.lift[F, S, A](G.empty[A])(G)
IndexedStateT.liftF[F, S, A](G.empty[A])(G)
}

private[data] sealed abstract class IndexedStateTMonadError[F[_], S, E] extends IndexedStateTMonad[F, S]
with MonadError[IndexedStateT[F, S, S, ?], E] {
implicit def F: MonadError[F, E]

def raiseError[A](e: E): IndexedStateT[F, S, S, A] = IndexedStateT.lift(F.raiseError(e))
def raiseError[A](e: E): IndexedStateT[F, S, S, A] = IndexedStateT.liftF(F.raiseError(e))

def handleErrorWith[A](fa: IndexedStateT[F, S, S, A])(f: E => IndexedStateT[F, S, S, A]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.handleErrorWith(fa.run(s))(e => f(e).run(s)))
Expand Down
19 changes: 18 additions & 1 deletion core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ object Kleisli extends KleisliInstances with KleisliFunctions with KleisliExplic

private[data] sealed trait KleisliFunctions {

def liftF[F[_], A, B](x: F[B]): Kleisli[F, A, B] =
Kleisli(_ => x)

/**
* Same as [[liftF]], but expressed as a FunctionK for use with mapK
* {{{
* scala> import cats._, data._, implicits._
* scala> val a: Kleisli[Eval, String, Int] = 1.pure[Kleisli[Eval, String, ?]]
* scala> val b: Kleisli[OptionT[Eval, ?], String, Int] = a.mapK(OptionT.liftK)
* scala> b.run("").value.value
* res0: Option[Int] = Some(1)
* }}}
*/
def liftK[F[_], A]: F ~> Kleisli[F, A, ?] =
λ[F ~> Kleisli[F, A, ?]](Kleisli.liftF(_))

@deprecated("Use liftF instead", "1.0.0")
def lift[F[_], A, B](x: F[B]): Kleisli[F, A, B] =
Kleisli(_ => x)

Expand Down Expand Up @@ -287,7 +304,7 @@ private[data] sealed trait KleisliSemigroupK[F[_], A] extends SemigroupK[Kleisli
private[data] sealed trait KleisliMonoidK[F[_], A] extends MonoidK[Kleisli[F, A, ?]] with KleisliSemigroupK[F, A] {
implicit def F: MonoidK[F]

override def empty[B]: Kleisli[F, A, B] = Kleisli.lift(F.empty[B])
override def empty[B]: Kleisli[F, A, B] = Kleisli.liftF(F.empty[B])
}

private[data] trait KleisliAlternative[F[_], A] extends Alternative[Kleisli[F, A, ?]] with KleisliApplicative[F, A] with KleisliMonoidK[F, A] {
Expand Down
13 changes: 13 additions & 0 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,19 @@ object OptionT extends OptionTInstances {
* Lifts the `F[A]` Functor into an `OptionT[F, A]`.
*/
def liftF[F[_], A](fa: F[A])(implicit F: Functor[F]): OptionT[F, A] = OptionT(F.map(fa)(Some(_)))

/**
* Same as [[liftF]], but expressed as a FunctionK for use with mapK
* {{{
* scala> import cats._, data._, implicits._
* scala> val a: EitherT[Eval, String, Int] = 1.pure[EitherT[Eval, String, ?]]
* scala> val b: EitherT[OptionT[Eval, ?], String, Int] = a.mapK(OptionT.liftK)
* scala> b.value.value.value
* res0: Option[Either[String,Int]] = Some(Right(1))
* }}}
*/
def liftK[F[_]](implicit F: Functor[F]): F ~> OptionT[F, ?] =
λ[F ~> OptionT[F, ?]](OptionT.liftF(_))
}

private[data] sealed abstract class OptionTInstances extends OptionTInstances0 {
Expand Down
17 changes: 17 additions & 0 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@ final case class WriterT[F[_], L, V](run: F[(L, V)]) {

object WriterT extends WriterTInstances with WriterTFunctions {

def liftF[F[_], L, V](fv: F[V])(implicit monoidL: Monoid[L], F: Applicative[F]): WriterT[F, L, V] =
WriterT(F.map(fv)(v => (monoidL.empty, v)))

/**
* Same as [[liftF]], but expressed as a FunctionK for use with mapK
* {{{
* scala> import cats._, data._, implicits._
* scala> val a: OptionT[Eval, Int] = 1.pure[OptionT[Eval, ?]]
* scala> val b: OptionT[WriterT[Eval, String, ?], Int] = a.mapK(WriterT.liftK)
* scala> b.value.run.value
* res0: (String, Option[Int]) = ("",Some(1))
* }}}
*/
def liftK[F[_], L](implicit monoidL: Monoid[L], F: Applicative[F]): F ~> WriterT[F, L, ?] =
λ[F ~> WriterT[F, L, ?]](WriterT.liftF(_))

@deprecated("Use liftF instead", "1.0.0")
def lift[F[_], L, V](fv: F[V])(implicit monoidL: Monoid[L], F: Applicative[F]): WriterT[F, L, V] =
WriterT(F.map(fv)(v => (monoidL.empty, v)))

Expand Down
2 changes: 2 additions & 0 deletions scalafix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ sbt scalafix github:typelevel/cats/v1.0.0

- [x] EitherT.liftT was renamed to EitherT.liftF

- [x] the lift method on WriterT, StateT, RWST and Kleisli was renamed to liftF

- [x] CartesianBuilder (i.e. |@|) syntax is deprecated, use the apply syntax on tuples instead. E.g. (x |@| y |@| z).map(...) should be replaced by (x, y, z).mapN(...)

- [x] Free.suspend is renamed to Free.defer for consistency.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
rule = "scala:fix.v1_0_0.RenameTransformersLift"
*/
package fix
package to1_0_0

object RenameTransformersLiftTests {
import cats.instances.option._
import cats.instances.string._
import cats.data.{Kleisli, StateT, WriterT}

val fa: Option[Int] = Some(42)
val k: Kleisli[Option, Nothing, Int] = Kleisli.lift(fa)
val w: WriterT[Option, String, Int] = WriterT.lift(fa)
val s: StateT[Option, Nothing, Int] = StateT.lift(fa)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fix
package to1_0_0

object RenameTransformersLiftTests {
import cats.instances.option._
import cats.instances.string._
import cats.data.{Kleisli, StateT, WriterT}

val fa: Option[Int] = Some(42)
val k: Kleisli[Option, Nothing, Int] = Kleisli.liftF(fa)
val w: WriterT[Option, String, Int] = WriterT.liftF(fa)
val s: StateT[Option, Nothing, Int] = StateT.liftF(fa)
}
16 changes: 16 additions & 0 deletions scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,22 @@ case class RenameEitherTLiftT(index: SemanticdbIndex)

}

// ref: https://github.com/typelevel/cats/pull/2033
case class RenameTransformersLift(index: SemanticdbIndex)
extends SemanticRule(index, "RenameTransformersLift") {

override def fix(ctx: RuleCtx): Patch =
ctx.replaceSymbols(
"_root_.cats.data.WriterT.lift." -> "liftF",
"_root_.cats.data.StateT.lift." -> "liftF",
"_root_.cats.data.CommonStateTConstructors.lift." -> "liftF",
"_root_.cats.data.CommonIRWSTConstructors.lift." -> "liftF",
"_root_.cats.data.KleisliFunctions.lift." -> "liftF"
)

}


// ref: https://github.com/typelevel/cats/pull/1961
case class RenameCartesian(index: SemanticdbIndex)
extends SemanticRule(index, "RenameCartesian") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ class ReaderWriterStateTSuite extends CatsSuite {
}
}

test("ReaderWriterState.pure, ReaderWriterStateT.lift and IndexedReaderWriterStateT.lift are consistent") {
test("ReaderWriterState.pure, ReaderWriterStateT.liftF and IndexedReaderWriterStateT.liftF are consistent") {
forAll { (value: Int) =>
val rws: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterState.pure(value)
val rwst: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterStateT.lift(Eval.now(value))
val irwst: ReaderWriterState[String, Vector[String], Int, Int] = IndexedReaderWriterStateT.lift(Eval.now(value))
val rwst: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterStateT.liftF(Eval.now(value))
val irwst: ReaderWriterState[String, Vector[String], Int, Int] = IndexedReaderWriterStateT.liftF(Eval.now(value))

rws should === (rwst)
rwst should === (irwst)
Expand Down
6 changes: 3 additions & 3 deletions tests/src/test/scala/cats/tests/IndexedStateTSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,11 @@ class IndexedStateTSuite extends CatsSuite {
}
}

test("State.pure, StateT.lift and IndexedStateT.lift are consistent") {
test("State.pure, StateT.liftF and IndexedStateT.liftF are consistent") {
forAll { (s: String, i: Int) =>
val state: State[String, Int] = State.pure(i)
val stateT: State[String, Int] = StateT.lift(Eval.now(i))
val indexedStateT: State[String, Int] = IndexedStateT.lift(Eval.now(i))
val stateT: State[String, Int] = StateT.liftF(Eval.now(i))
val indexedStateT: State[String, Int] = IndexedStateT.liftF(Eval.now(i))

state.run(s) should === (stateT.run(s))
state.run(s) should === (indexedStateT.run(s))
Expand Down
4 changes: 2 additions & 2 deletions tests/src/test/scala/cats/tests/ParallelSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest {
}

test("WriterT with Either should accumulate errors") {
val w1: WriterT[Either[String, ?], String, Int] = WriterT.lift(Left("Too "))
val w2: WriterT[Either[String, ?], String, Int] = WriterT.lift(Left("bad."))
val w1: WriterT[Either[String, ?], String, Int] = WriterT.liftF(Left("Too "))
val w2: WriterT[Either[String, ?], String, Int] = WriterT.liftF(Left("bad."))

((w1,w2).parMapN(_ + _).value) should === (Left("Too bad."))

Expand Down
4 changes: 2 additions & 2 deletions tests/src/test/scala/cats/tests/WriterTSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ class WriterTSuite extends CatsSuite {
}
}

test("Writer.pure and WriterT.lift are consistent") {
test("Writer.pure and WriterT.liftF are consistent") {
forAll { (i: Int) =>
val writer: Writer[String, Int] = Writer.value(i)
val writerT: WriterT[Option, String, Int] = WriterT.lift(Some(i))
val writerT: WriterT[Option, String, Int] = WriterT.liftF(Some(i))
writer.run.some should === (writerT.run)
}
}
Expand Down