diff --git a/build.sbt b/build.sbt index 4bfd038b5..1d7f8b916 100644 --- a/build.sbt +++ b/build.sbt @@ -1,7 +1,7 @@ import Publish._, Dependencies._ import com.typesafe.sbt.SbtGit.git -val libVersion = "0.7.1" +val libVersion = "0.7.2" lazy val setMinorVersion = minorVersion := { CrossVersion.partialVersion(scalaVersion.value) match { diff --git a/concurrent/src/main/scala/tofu/concurrent/Atom.scala b/concurrent/src/main/scala/tofu/concurrent/Atom.scala index 98ea0d78c..494b69165 100644 --- a/concurrent/src/main/scala/tofu/concurrent/Atom.scala +++ b/concurrent/src/main/scala/tofu/concurrent/Atom.scala @@ -10,7 +10,7 @@ import tofu.syntax.monadic._ import tofu.syntax.bracket._ /** a middleground between cats.concurrent.Ref and zio.Ref */ -trait Atom[F[_], A] { +trait Atom[+F[_], A] { /** * Obtains the current value. diff --git a/concurrent/src/main/scala/tofu/concurrent/ContextT.scala b/concurrent/src/main/scala/tofu/concurrent/ContextT.scala new file mode 100644 index 000000000..c61427553 --- /dev/null +++ b/concurrent/src/main/scala/tofu/concurrent/ContextT.scala @@ -0,0 +1,118 @@ +package tofu.concurrent +import cats._ +import cats.effect._ +import cats.instances.either._ +import tofu.HasContextRun +import tofu.concurrent.impl._ +import tofu.syntax.functionk.funKFrom +import tofu.syntax.monadic._ + +/** a ReaderT analog, allowing to have context referring resulting type + * for instance you can define ```MyCtx[F[_]](state: Ref[F, Int], k ``` + * + * */ +trait ContextT[F[+_], C[_[_]], +A] { + + /** run computation, providing context */ + def run(c: C[ContextT[F, C, +*]]): F[A] +} + +object ContextT extends ContextTInstances { + private def makeLiftF[F[+_], C[_[_]]]: F ~> ContextT[F, C, *] = funKFrom[F](fa => _ => fa) + private val liftFAny = makeLiftF[Any, Any] + + /** lift pure value to reader */ + def pure[F[+_]: Applicative, C[_[_]], A](a: A): ContextT[F, C, A] = _ => a.pure[F] + + /** acquire context */ + def ask[F[+_]: Applicative, C[_[_]]]: ContextT[F, C, C[ContextT[F, C, *]]] = _.pure[F] + + /** get some value from context */ + def provide[F[+_]: Applicative, C[_[_]], A](f: C[ContextT[F, C, *]] => A): ContextT[F, C, A] = c => f(c).pure[F] + + /** construct some process from context */ + def provideF[F[+_], C[_[_]], A](f: C[ContextT[F, C, *]] => F[A]): ContextT[F, C, A] = c => f(c) + + /** construct some process, using resulting type */ + def provideM[F[+_], C[_[_]], A](f: C[ContextT[F, C, *]] => ContextT[F, C, A]): ContextT[F, C, A] = c => f(c).run(c) + + /** Natural transformation for lifting underlying values to contextual */ + def liftF[F[+_], C[_[_]]]: F ~> ContextT[F, C, *] = liftFAny.asInstanceOf[F ~> ContextT[F, C, *]] + + /** lift underlying value to contextual */ + def lift[F[+_], C[_[_]], A](fa: F[A]): ContextT[F, C, A] = _ => fa +} +trait ContextTInstances extends ContextTInstancesQ + +trait ContextTInstancesZ { + final implicit def contextTInvariant[F[+_]: Invariant, C[_[_]]]: Invariant[ContextT[F, C, *]] = new ContextTInvariantI +} + +trait ContextTInstancesY { + final implicit def contextTFunctor[F[+_]: Functor, C[_[_]]]: Functor[ContextT[F, C, *]] = new ContextTFunctorI + + final implicit def contextTInvariantSemigroupal[F[+_]: InvariantSemigroupal, C[_[_]]] + : InvariantSemigroupal[ContextT[F, C, *]] = new ContextTInvariantSemigroupalI + + final implicit def contextTSemigroupK[F[+_]: SemigroupK, C[_[_]]]: SemigroupK[ContextT[F, C, *]] = + new ContextTSemigroupKI +} + +trait ContextTInstancesX extends ContextTInstancesY { + final implicit def contextTApply[F[+_]: Apply, C[_[_]]]: Apply[ContextT[F, C, *]] = new ContextTApplyI + final implicit def contextTMonoidK[F[+_]: MonoidK, C[_[_]]]: MonoidK[ContextT[F, C, *]] = new ContextTMonoidKI + final implicit def contextTcoflatMap[F[+_]: CoflatMap, C[_[_]]]: CoflatMap[ContextT[F, C, *]] = new ContextTCoflatMapI + + final implicit def contextTInvariantMonoidal[F[+_]: InvariantMonoidal, C[_[_]]] + : InvariantMonoidal[ContextT[F, C, *]] = new ContextTInvariantMonoidalI +} + +trait ContextTInstancesW extends ContextTInstancesX { + final implicit def contextTApplicative[F[+_]: Applicative, C[_[_]]]: Applicative[ContextT[F, C, *]] = + new ContextTApplicativeI + + final implicit def contextTFlatMap[F[+_]: FlatMap, C[_[_]]]: FlatMap[ContextT[F, C, *]] = new ContextTFlatMapI +} + +trait ContextTInstancesV extends ContextTInstancesW { + final implicit def contextTMonad[F[+_]: Monad, C[_[_]]]: Monad[ContextT[F, C, *]] = new ContextTMonadI + + final implicit def contextTAlternative[F[+_]: Alternative, C[_[_]]]: Alternative[ContextT[F, C, *]] = + new ContextTAlternativeI + + final implicit def contextTApplicativeError[F[+_]: ApplicativeError[*[_], E], C[_[_]], E] + : ApplicativeError[ContextT[F, C, *], E] = + new ContextTApplicativeErrorI +} + +trait ContextTInstancesU extends ContextTInstancesV { + final implicit def contextTMonadError[F[+_]: MonadError[*[_], E], C[_[_]], E]: MonadError[ContextT[F, C, *], E] = + new ContextTMonadErrorI +} + +trait ContextTInstancesT extends ContextTInstancesU { + final implicit def contextTBracket[F[+_]: Bracket[*[_], E], C[_[_]], E]: Bracket[ContextT[F, C, *], E] = + new ContextTBracketI +} + +trait ContextTInstancesS extends ContextTInstancesT { + final implicit def contextTSync[F[+_]: Sync, C[_[_]]]: Sync[ContextT[F, C, *]] = new ContextTSyncI + final implicit def contextTLiftIO[F[+_]: LiftIO, C[_[_]]]: LiftIO[ContextT[F, C, *]] = new ContextTLiftIOI +} + +trait ContextTInstancesR extends ContextTInstancesS { + final implicit def contextTAsync[F[+_]: Async, C[_[_]]]: Async[ContextT[F, C, *]] = new ContextTAsyncI + + final def contextTContext[F[+_]: Applicative, C[_[_]]]: ContextTContext[F, C] = new ContextTContext +} + +trait ContextTInstancesQ extends ContextTInstancesR { + final implicit def contextTConcurrent[F[+_]: Concurrent, C[_[_]]]: Concurrent[ContextT[F, C, *]] = + new ContextTConcurrentI + + final implicit def contextTRunContext[F[+_]: Applicative: Defer, C[_[_]]]: ContextTRunContext[F, C] = + new ContextTRunContext + + final def runContextUnsafe[F[+_]: Applicative, C[_[_]]]: HasContextRun[ContextT[F, C, *], F, C[ContextT[F, C, *]]] = + new ContextTRunContextUnsafe[F, C] +} diff --git a/concurrent/src/main/scala/tofu/concurrent/QVar.scala b/concurrent/src/main/scala/tofu/concurrent/QVar.scala index 7e8c9c448..0b423cd80 100644 --- a/concurrent/src/main/scala/tofu/concurrent/QVar.scala +++ b/concurrent/src/main/scala/tofu/concurrent/QVar.scala @@ -8,7 +8,7 @@ import tofu.higherKind.{RepresentableK, derived} import tofu.syntax.monadic._ /** a middleground between cats.concurrent.MVar and zio.Queue.bounded(1) */ -trait QVar[F[_], A] { +trait QVar[+F[_], A] { /** * Returns `true` if the `MVar` is empty and can receive a `put`, or diff --git a/concurrent/src/main/scala/tofu/concurrent/impl/FocusedRef.scala b/concurrent/src/main/scala/tofu/concurrent/impl/FocusedRef.scala index 778e2e442..db878a445 100644 --- a/concurrent/src/main/scala/tofu/concurrent/impl/FocusedRef.scala +++ b/concurrent/src/main/scala/tofu/concurrent/impl/FocusedRef.scala @@ -12,8 +12,8 @@ final case class FocusedRef[F[_]: Functor, A, B](ref: Ref[F, A], focus: Contains focus.set(a, next) -> res } - def get: F[B] = ref.get.map(focus.extract) - def set(b: B): F[Unit] = ref.update(a => focus.set(a, b)) + def get: F[B] = ref.get.map(focus.extract) + def set(b: B): F[Unit] = ref.update(a => focus.set(a, b)) def update(f: B => B): F[Unit] = ref.update(focus.update(_, f)) def modify[X](f: B => (B, X)): F[X] = ref.modify(focusedMod(f)) diff --git a/concurrent/src/main/scala/tofu/concurrent/impl/contextt.scala b/concurrent/src/main/scala/tofu/concurrent/impl/contextt.scala new file mode 100644 index 000000000..f1315072c --- /dev/null +++ b/concurrent/src/main/scala/tofu/concurrent/impl/contextt.scala @@ -0,0 +1,331 @@ +package tofu.concurrent +package impl +import cats.effect._ +import cats.instances.either._ +import cats.instances.tuple._ +import cats.syntax.bifunctor._ +import cats._ +import tofu.{Context, HasContextRun, RunContext} +import tofu.syntax.functionk.funKFrom +import tofu.syntax.monadic._ + +trait ContextTInvariant[F[+_], C[_[_]]] extends Invariant[ContextT[F, C, *]] { + implicit def F: Invariant[F] + final override def imap[A, B](fa: ContextT[F, C, A])(f: A => B)(g: B => A): ContextT[F, C, B] = c => + F.imap(fa.run(c))(f)(g) +} + +final class ContextTInvariantI[F[+_], C[_[_]]](implicit val F: Invariant[F]) extends ContextTInvariant[F, C] + +trait ContextTFunctor[F[+_], C[_[_]]] extends Functor[ContextT[F, C, *]] with ContextTInvariant[F, C] { + implicit def F: Functor[F] + + final override def map[A, B](fa: ContextT[F, C, A])(f: A => B): ContextT[F, C, B] = fa.run(_).map(f) + final override def void[A](fa: ContextT[F, C, A]): ContextT[F, C, Unit] = fa.run(_).void + + final override def widen[A, B >: A](fa: ContextT[F, C, A]): ContextT[F, C, B] = fa + + final override def as[A, B](fa: ContextT[F, C, A], b: B): ContextT[F, C, B] = c => fa.run(c).as(b) + final override def tupleLeft[A, B](fa: ContextT[F, C, A], b: B): ContextT[F, C, (B, A)] = fa.run(_).tupleLeft(b) + + override def fproduct[A, B](fa: ContextT[F, C, A])(f: A => B): ContextT[F, C, (A, B)] = fa.run(_).fproduct(f) + override def tupleRight[A, B](fa: ContextT[F, C, A], b: B): ContextT[F, C, (A, B)] = fa.run(_).tupleRight(b) + override def ifF[A](fb: ContextT[F, C, Boolean])(ifTrue: => A, ifFalse: => A): ContextT[F, C, A] = c => + F.ifF(fb.run(c))(ifTrue, ifFalse) +} + +trait ContextTInvariantSemigroupal[F[+_], C[_[_]]] + extends InvariantSemigroupal[ContextT[F, C, *]] with ContextTInvariant[F, C] { + implicit def F: InvariantSemigroupal[F] + + final override def product[A, B](fa: ContextT[F, C, A], fb: ContextT[F, C, B]): ContextT[F, C, (A, B)] = + c => F.product(fa.run(c), fb.run(c)) +} + +final class ContextTInvariantSemigroupalI[F[+_], C[_[_]]](implicit val F: InvariantSemigroupal[F]) + extends ContextTInvariantSemigroupal[F, C] + +trait ContextTInvariantMonoidal[F[+_], C[_[_]]] + extends InvariantMonoidal[ContextT[F, C, *]] with ContextTInvariantSemigroupal[F, C] { + implicit def F: InvariantMonoidal[F] + + final override val unit: ContextT[F, C, Unit] = _ => F.unit + final override def point[A](a: A): ContextT[F, C, A] = _ => F.point(a) +} + +final class ContextTInvariantMonoidalI[F[+_], C[_[_]]](implicit val F: InvariantMonoidal[F]) + extends ContextTInvariantMonoidal[F, C] + +final class ContextTFunctorI[F[+_], C[_[_]]](implicit val F: Functor[F]) extends ContextTFunctor[F, C] + +trait ContextTApply[F[+_], C[+_[_]]] + extends Apply[ContextT[F, C, *]] with ContextTFunctor[F, C] with ContextTInvariantSemigroupal[F, C] { + implicit def F: Apply[F] + final override def ap[A, B](ff: ContextT[F, C, A => B])(fa: ContextT[F, C, A]): ContextT[F, C, B] = + c => ff.run(c) ap fa.run(c) + + final override def map2[A, B, Z](fa: ContextT[F, C, A], fb: ContextT[F, C, B])(f: (A, B) => Z): ContextT[F, C, Z] = + c => fa.run(c).map2(fb.run(c))(f) + + final override def productR[A, B](fa: ContextT[F, C, A])(fb: ContextT[F, C, B]): ContextT[F, C, B] = + c => fa.run(c).productR(fb.run(c)) + final override def productL[A, B](fa: ContextT[F, C, A])(fb: ContextT[F, C, B]): ContextT[F, C, A] = + c => fa.run(c).productL(fb.run(c)) + + final override def ap2[A, B, Z]( + ff: ContextT[F, C, (A, B) => Z] + )(fa: ContextT[F, C, A], fb: ContextT[F, C, B]): ContextT[F, C, Z] = + c => ff.run(c).ap2(fa.run(c), fb.run(c)) + final override def map2Eval[A, B, Z](fa: ContextT[F, C, A], fb: Eval[ContextT[F, C, B]])( + f: (A, B) => Z + ): Eval[ContextT[F, C, Z]] = + Eval.always(c => fa.run(c).map2Eval(fb.map(_.run(c)))(f).value) + final override def ifA[A]( + fcond: ContextT[F, C, Boolean] + )(ifTrue: ContextT[F, C, A], ifFalse: ContextT[F, C, A]): ContextT[F, C, A] = + c => F.ifA(fcond.run(c))(ifTrue.run(c), ifFalse.run(c)) +} + +final class ContextTApplyI[F[+_], C[_[_]]](implicit val F: Apply[F]) extends ContextTApply[F, C] + +trait ContextTApplicative[F[+_], C[_[_]]] + extends Applicative[ContextT[F, C, *]] with ContextTApply[F, C] with ContextTInvariantMonoidal[F, C] { + implicit def F: Applicative[F] + final override def pure[A](x: A): ContextT[F, C, A] = _ => x.pure[F] + + final override def replicateA[A](n: Int, fa: ContextT[F, C, A]): ContextT[F, C, List[A]] = fa.run(_).replicateA(n) + final override def unlessA[A](cond: Boolean)(f: => ContextT[F, C, A]): ContextT[F, C, Unit] = c => + F.unlessA(cond)(f.run(c)) + final override def whenA[A](cond: Boolean)(f: => ContextT[F, C, A]): ContextT[F, C, Unit] = c => + F.whenA(cond)(f.run(c)) +} + +final class ContextTApplicativeI[F[+_], C[_[_]]](implicit val F: Applicative[F]) extends ContextTApplicative[F, C] + +trait ContextTFlatMap[F[+_], C[_[_]]] extends FlatMap[ContextT[F, C, *]] with ContextTApply[F, C] { + implicit def F: FlatMap[F] + + final override def flatMap[A, B](fa: ContextT[F, C, A])(f: A => ContextT[F, C, B]): ContextT[F, C, B] = + c => fa.run(c).flatMap(f(_).run(c)) + + final override def tailRecM[A, B](a: A)(f: A => ContextT[F, C, Either[A, B]]): ContextT[F, C, B] = + c => a.tailRecM(a => f(a).run(c)) + + final override def flatten[A](ffa: ContextT[F, C, ContextT[F, C, A]]): ContextT[F, C, A] = + c => ffa.run(c).flatMap(_.run(c)) + + final override def productREval[A, B](fa: ContextT[F, C, A])(fb: Eval[ContextT[F, C, B]]): ContextT[F, C, B] = + c => F.productREval(fa.run(c))(fb.map(_.run(c))) + final override def productLEval[A, B](fa: ContextT[F, C, A])(fb: Eval[ContextT[F, C, B]]): ContextT[F, C, A] = + c => F.productLEval(fa.run(c))(fb.map(_.run(c))) + final override def mproduct[A, B](fa: ContextT[F, C, A])(f: A => ContextT[F, C, B]): ContextT[F, C, (A, B)] = + c => F.mproduct(fa.run(c))(a => f(a).run(c)) + final override def ifM[B]( + fa: ContextT[F, C, Boolean] + )(ifTrue: => ContextT[F, C, B], ifFalse: => ContextT[F, C, B]): ContextT[F, C, B] = + c => F.ifM(fa.run(c))(ifTrue.run(c), ifFalse.run(c)) + final override def flatTap[A, B](fa: ContextT[F, C, A])(f: A => ContextT[F, C, B]): ContextT[F, C, A] = + c => F.flatTap(fa.run(c))(a => f(a).run(c)) + final override def foreverM[A, B](fa: ContextT[F, C, A]): ContextT[F, C, B] = + c => F.foreverM(fa.run(c)) + final override def iterateForeverM[A, B](a: A)(f: A => ContextT[F, C, A]): ContextT[F, C, B] = + c => F.iterateForeverM(a)(a => f(a).run(c)) + final override def untilDefinedM[A](foa: ContextT[F, C, Option[A]]): ContextT[F, C, A] = + c => F.untilDefinedM(foa.run(c)) +} + +final class ContextTFlatMapI[F[+_], C[_[_]]](implicit val F: FlatMap[F]) extends ContextTFlatMap[F, C] + +trait ContextTMonad[F[+_], C[_[_]]] + extends Monad[ContextT[F, C, *]] with ContextTApplicative[F, C] with ContextTFlatMap[F, C] { + implicit def F: Monad[F] + + final override def whileM[G[_], A]( + p: ContextT[F, C, Boolean] + )(body: => ContextT[F, C, A])(implicit G: Alternative[G]): ContextT[F, C, G[A]] = + c => F.whileM(p.run(c))(body.run(c)) + final override def whileM_[A](p: ContextT[F, C, Boolean])(body: => ContextT[F, C, A]): ContextT[F, C, Unit] = + c => F.whileM_(p.run(c))(body.run(c)) + final override def untilM[G[_], A]( + f: ContextT[F, C, A] + )(cond: => ContextT[F, C, Boolean])(implicit G: Alternative[G]): ContextT[F, C, G[A]] = + c => F.untilM(f.run(c))(cond.run(c)) + final override def untilM_[A](f: ContextT[F, C, A])(cond: => ContextT[F, C, Boolean]): ContextT[F, C, Unit] = + c => F.untilM_(f.run(c))(cond.run(c)) + final override def iterateWhile[A](f: ContextT[F, C, A])(p: A => Boolean): ContextT[F, C, A] = + f.run(_).iterateWhile(p) + final override def iterateUntil[A](f: ContextT[F, C, A])(p: A => Boolean): ContextT[F, C, A] = + f.run(_).iterateUntil(p) + final override def iterateWhileM[A](init: A)(f: A => ContextT[F, C, A])(p: A => Boolean): ContextT[F, C, A] = + c => F.iterateWhileM(init)(f(_).run(c))(p) + final override def iterateUntilM[A](init: A)(f: A => ContextT[F, C, A])(p: A => Boolean): ContextT[F, C, A] = + c => F.iterateUntilM(init)(f(_).run(c))(p) +} + +final class ContextTMonadI[F[+_], C[_[_]]](implicit val F: Monad[F]) extends ContextTMonad[F, C] + +trait ContextTApplicativeError[F[+_], C[_[_]], E] + extends ApplicativeError[ContextT[F, C, *], E] with ContextTApplicative[F, C] { + implicit def F: ApplicativeError[F, E] + final override def raiseError[A](e: E): ContextT[F, C, A] = _ => F.raiseError(e) + final override def handleErrorWith[A](fa: ContextT[F, C, A])(f: E => ContextT[F, C, A]): ContextT[F, C, A] = + c => F.handleErrorWith(fa.run(c))(e => f(e).run(c)) + +} + +trait ContextTSemigroupK[F[+_], C[_[_]]] extends SemigroupK[ContextT[F, C, *]] { + implicit def F: SemigroupK[F] + + final override def combineK[A](x: ContextT[F, C, A], y: ContextT[F, C, A]): ContextT[F, C, A] = c => + F.combineK(x.run(c), y.run(c)) +} + +final class ContextTSemigroupKI[F[+_], C[_[_]]](implicit val F: SemigroupK[F]) extends ContextTSemigroupK[F, C] + +trait ContextTMonoidK[F[+_], C[_[_]]] extends MonoidK[ContextT[F, C, *]] with ContextTSemigroupK[F, C] { + implicit def F: MonoidK[F] + private[this] val emptyAny: ContextT[F, C, Any] = _ => F.empty[Any] + + final override def empty[A]: ContextT[F, C, A] = emptyAny.asInstanceOf[ContextT[F, C, A]] +} + +final class ContextTMonoidKI[F[+_], C[_[_]]](implicit val F: MonoidK[F]) extends ContextTMonoidK[F, C] + +trait ContextTAlternative[F[+_], C[_[_]]] + extends Alternative[ContextT[F, C, *]] with ContextTMonoidK[F, C] with ContextTApplicative[F, C] { + implicit def F: Alternative[F] +} + +final class ContextTAlternativeI[F[+_], C[_[_]]](implicit val F: Alternative[F]) extends ContextTAlternative[F, C] + +trait ContextTCoflatMap[F[+_], C[_[_]]] extends CoflatMap[ContextT[F, C, *]] with ContextTFunctor[F, C] { + implicit def F: CoflatMap[F] + + def coflatMap[A, B](fa: ContextT[F, C, A])(f: ContextT[F, C, A] => B): ContextT[F, C, B] = + c => F.coflatMap(fa.run(c))(fa => f(_ => fa)) +} + +final class ContextTCoflatMapI[F[+_], C[_[_]]](implicit val F: CoflatMap[F]) extends ContextTCoflatMap[F, C] + +final class ContextTApplicativeErrorI[F[+_], C[_[_]], E](implicit val F: ApplicativeError[F, E]) + extends ContextTApplicativeError[F, C, E] + +trait ContextTMonadError[F[+_], C[_[_]], E] + extends MonadError[ContextT[F, C, *], E] with ContextTMonad[F, C] with ContextTApplicativeError[F, C, E] { + implicit def F: MonadError[F, E] + final override def ensure[A](fa: ContextT[F, C, A])(error: => E)(predicate: A => Boolean): ContextT[F, C, A] = + c => F.ensure(fa.run(c))(error)(predicate) + final override def ensureOr[A](fa: ContextT[F, C, A])(error: A => E)(predicate: A => Boolean): ContextT[F, C, A] = + c => F.ensureOr(fa.run(c))(error)(predicate) + final override def rethrow[A, EE <: E](fa: ContextT[F, C, Either[EE, A]]): ContextT[F, C, A] = + c => F.rethrow(fa.run(c)) + final override def redeemWith[A, B]( + fa: ContextT[F, C, A] + )(recover: E => ContextT[F, C, B], bind: A => ContextT[F, C, B]): ContextT[F, C, B] = + c => F.redeemWith(fa.run(c))(e => recover(e).run(c), a => bind(a).run(c)) + final override def adaptError[A](fa: ContextT[F, C, A])(pf: PartialFunction[E, E]): ContextT[F, C, A] = + c => F.adaptError(fa.run(c))(pf) +} + +final class ContextTMonadErrorI[F[+_], C[_[_]], E](implicit val F: MonadError[F, E]) extends ContextTMonadError[F, C, E] + +trait ContextTBracket[F[+_], C[_[_]], E] extends Bracket[ContextT[F, C, *], E] with ContextTMonadError[F, C, E] { + implicit def F: Bracket[F, E] + + final override def bracketCase[A, B]( + acquire: ContextT[F, C, A] + )(use: A => ContextT[F, C, B])(release: (A, ExitCase[E]) => ContextT[F, C, Unit]): ContextT[F, C, B] = + c => F.bracketCase(acquire.run(c))(a => use(a).run(c))((a, ec) => release(a, ec).run(c)) + final override def bracket[A, B]( + acquire: ContextT[F, C, A] + )(use: A => ContextT[F, C, B])(release: A => ContextT[F, C, Unit]): ContextT[F, C, B] = + c => F.bracket(acquire.run(c))(a => use(a).run(c))(a => release(a).run(c)) + final override def uncancelable[A](fa: ContextT[F, C, A]): ContextT[F, C, A] = + c => F.uncancelable(fa.run(c)) + final override def guarantee[A](fa: ContextT[F, C, A])(finalizer: ContextT[F, C, Unit]): ContextT[F, C, A] = + c => F.guarantee(fa.run(c))(finalizer.run(c)) + final override def guaranteeCase[A]( + fa: ContextT[F, C, A] + )(finalizer: ExitCase[E] => ContextT[F, C, Unit]): ContextT[F, C, A] = + c => F.guaranteeCase(fa.run(c))(ec => finalizer(ec).run(c)) + final override def onCancel[A](fa: ContextT[F, C, A])(finalizer: ContextT[F, C, Unit]): ContextT[F, C, A] = + c => F.onCancel(fa.run(c))(finalizer.run(c)) +} + +final class ContextTBracketI[F[+_], C[_[_]], E](implicit val F: Bracket[F, E]) extends ContextTBracket[F, C, E] + +trait ContextTSync[F[+_], C[_[_]]] extends Sync[ContextT[F, C, *]] with ContextTBracket[F, C, Throwable] { + implicit def F: Sync[F] + + final override def suspend[A](thunk: => ContextT[F, C, A]): ContextT[F, C, A] = c => F.suspend(thunk.run(c)) + final override def delay[A](thunk: => A): ContextT[F, C, A] = _ => F.delay(thunk) +} + +final class ContextTSyncI[F[+_], C[_[_]]](implicit val F: Sync[F]) extends ContextTSync[F, C] + +trait ContextTLiftIO[F[+_], C[_[_]]] extends LiftIO[ContextT[F, C, *]] { + implicit def F: LiftIO[F] + final override def liftIO[A](ioa: IO[A]): ContextT[F, C, A] = _ => F.liftIO(ioa) + +} + +final class ContextTLiftIOI[F[+_], C[_[_]]](implicit val F: LiftIO[F]) extends ContextTLiftIO[F, C] + +trait ContextTAsync[F[+_], C[_[_]]] extends Async[ContextT[F, C, *]] with ContextTLiftIO[F, C] with ContextTSync[F, C] { + implicit def F: Async[F] + final override def async[A](k: (Either[Throwable, A] => Unit) => Unit): ContextT[F, C, A] = _ => F.async(k) + final override def asyncF[A](k: (Either[Throwable, A] => Unit) => ContextT[F, C, Unit]): ContextT[F, C, A] = + c => F.asyncF(cb => k(cb).run(c)) + final override def never[A]: ContextT[F, C, A] = _ => F.never +} +final class ContextTAsyncI[F[+_], C[_[_]]](implicit val F: Async[F]) extends ContextTAsync[F, C] + +trait ContextTConcurrent[F[+_], C[_[_]]] extends Concurrent[ContextT[F, C, *]] with ContextTAsync[F, C] { + implicit def F: Concurrent[F] + final override def start[A](fa: ContextT[F, C, A]): ContextT[F, C, Fiber[ContextT[F, C, *], A]] = + c => F.start(fa.run(c)).map(_.mapK(ContextT.liftF)) + final override def racePair[A, B]( + fa: ContextT[F, C, A], + fb: ContextT[F, C, B] + ): ContextT[F, C, Either[(A, Fiber[ContextT[F, C, *], B]), (Fiber[ContextT[F, C, *], A], B)]] = + c => F.racePair(fa.run(c), fb.run(c)).map(_.bimap(_.map(_.mapK(ContextT.liftF)), _.leftMap(_.mapK(ContextT.liftF)))) + + final override def race[A, B](fa: ContextT[F, C, A], fb: ContextT[F, C, B]): ContextT[F, C, Either[A, B]] = + c => F.race(fa.run(c), fb.run(c)) + final override def cancelable[A]( + k: (Either[Throwable, A] => Unit) => CancelToken[ContextT[F, C, *]] + ): ContextT[F, C, A] = + c => F.cancelable(cb => k(cb).run(c)) + final override def continual[A, B]( + fa: ContextT[F, C, A] + )(f: Either[Throwable, A] => ContextT[F, C, B]): ContextT[F, C, B] = + c => F.continual(fa.run(c))(e => f(e).run(c)) +} + +final class ContextTConcurrentI[F[+_], C[_[_]]](implicit val F: Concurrent[F]) extends ContextTConcurrent[F, C] + +class ContextTContext[F[+_]: Applicative, C[_[_]]] extends Context[ContextT[F, C, *]] { + type Ctx = C[ContextT[F, C, *]] + val functor: Functor[ContextT[F, C, *]] = new ContextTFunctorI + + final def context: ContextT[F, C, C[ContextT[F, C, *]]] = _.pure[F] +} + +final class ContextTRunContext[F[+_]: Applicative, C[_[_]]](implicit FD: Defer[F]) + extends ContextTContext[F, C] with RunContext[ContextT[F, C, *]] { + type Lower[+A] = F[A] + + def runContext[A](fa: ContextT[F, C, A])(ctx: C[ContextT[F, C, *]]): F[A] = fa.run(ctx) + def local[A](fa: ContextT[F, C, A])(project: C[ContextT[F, C, *]] => C[ContextT[F, C, *]]): ContextT[F, C, A] = + c => FD.defer(fa.run(project(c))) +} + +// instance that does not defer locals. could be stack-unsafe +final class ContextTRunContextUnsafe[F[+_]: Applicative, C[_[_]]] + extends ContextTContext[F, C] with RunContext[ContextT[F, C, *]] { + type Lower[+A] = F[A] + + def runContext[A](fa: ContextT[F, C, A])(ctx: C[ContextT[F, C, *]]): F[A] = fa.run(ctx) + def local[A](fa: ContextT[F, C, A])(project: C[ContextT[F, C, *]] => C[ContextT[F, C, *]]): ContextT[F, C, A] = + c => fa.run(project(c)) +} diff --git a/config/src/main/scala/tofu/config/ConfigMonad.scala b/config/src/main/scala/tofu/config/ConfigMonad.scala index 78789f2f2..80c4148dd 100644 --- a/config/src/main/scala/tofu/config/ConfigMonad.scala +++ b/config/src/main/scala/tofu/config/ConfigMonad.scala @@ -11,7 +11,7 @@ import tofu.syntax.monadic._ import cats.MonadError import cats.Applicative import cats.~> -import tofu.syntax.functionK._ +import tofu.syntax.functionk._ import cats.syntax.applicativeError._ trait ConfigMonad[F[_]] { diff --git a/config/src/main/scala/tofu/config/typesafe.scala b/config/src/main/scala/tofu/config/typesafe.scala index 80aceddc7..6d91e9f46 100644 --- a/config/src/main/scala/tofu/config/typesafe.scala +++ b/config/src/main/scala/tofu/config/typesafe.scala @@ -8,7 +8,7 @@ import com.typesafe.config.{Config, ConfigValue} import scala.collection.JavaConverters._ import tofu.concurrent.Refs import tofu.syntax.monadic._ -import tofu.syntax.functionK._ +import tofu.syntax.functionk._ import cats.effect.SyncIO object typesafe { diff --git a/core/src/main/scala/tofu/lift/IsoK.scala b/core/src/main/scala/tofu/lift/IsoK.scala index 770392d34..e17a42319 100644 --- a/core/src/main/scala/tofu/lift/IsoK.scala +++ b/core/src/main/scala/tofu/lift/IsoK.scala @@ -1,7 +1,7 @@ package tofu.lift import cats.~> -import tofu.syntax.functionK._ +import tofu.syntax.functionk._ /** bidirectional transformation */ trait IsoK[F[_], G[_]] { self => diff --git a/core/src/test/scala/tofu/syntax/FoldableSuite.scala b/core/src/test/scala/tofu/syntax/FoldableSuite.scala index ff249dbf0..1e1c05308 100644 --- a/core/src/test/scala/tofu/syntax/FoldableSuite.scala +++ b/core/src/test/scala/tofu/syntax/FoldableSuite.scala @@ -1,6 +1,5 @@ package tofu.syntax -import org.scalatest.FlatSpec import cats.data.Writer import tofu.syntax.monadic._ import cats.data.Chain @@ -8,8 +7,9 @@ import cats.Monad import tofu.syntax.foldable._ import cats.instances.stream._ import cats.instances.int._ +import org.scalatest.flatspec.AnyFlatSpec -class FoldableSuite extends FlatSpec { +class FoldableSuite extends AnyFlatSpec { def add(s: Int, x: Int) = x > 0 whenOpt Writer.tell(Chain(s)).as(s + x) def look(x: Int) = x > 0 whenOpt Writer.tell(Chain(x)).as(x.toString) val elems = Stream.range(1, 10) #::: Stream.from(-1, -1) @@ -20,5 +20,5 @@ class FoldableSuite extends FlatSpec { ) "takeWhileM" should "filter elements" in - assert(elems.takeWhileM(look).run === (Chain.fromSeq(1 to 9), List.range(1, 10).map(_.toString))) + assert(elems.takeWhileM(look).run === ((Chain.fromSeq(1 to 9), List.range(1, 10).map(_.toString)))) } diff --git a/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala b/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala index 8b5e9cb18..a00f35892 100644 --- a/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala +++ b/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala @@ -15,7 +15,7 @@ import derevo.derive import org.scalatest.{FlatSpec, Matchers} import tofu.data.Embedded import tofu.syntax.embed._ -import tofu.syntax.functionK.funK +import tofu.syntax.functionk.funK import scala.util.Try diff --git a/env/src/main/scala/tofu/env/EnvInstances.scala b/env/src/main/scala/tofu/env/EnvInstances.scala index 1a12f8d56..e1d6f7768 100644 --- a/env/src/main/scala/tofu/env/EnvInstances.scala +++ b/env/src/main/scala/tofu/env/EnvInstances.scala @@ -4,10 +4,9 @@ import cats.arrow.{ArrowChoice, FunctionK, Profunctor} import cats.{Applicative, Monad, Parallel, ~>} import monix.eval.Task import monix.execution.Scheduler -import tofu.lift.{Unlift, UnsafeExecFuture} -import tofu.syntax.functionK._ -import tofu.lift.Unlift +import tofu.lift.UnsafeExecFuture import tofu.optics.Contains +import tofu.syntax.functionk._ import scala.concurrent.Future diff --git a/env/src/main/scala/tofu/env/EnvUnliftTask.scala b/env/src/main/scala/tofu/env/EnvUnliftTask.scala index ba5530145..32b86c1b9 100644 --- a/env/src/main/scala/tofu/env/EnvUnliftTask.scala +++ b/env/src/main/scala/tofu/env/EnvUnliftTask.scala @@ -3,7 +3,7 @@ import cats.~> import monix.eval.Task import tofu.lift.Unlift import tofu.optics.Contains -import tofu.syntax.functionK.funK +import tofu.syntax.functionk.funK class EnvUnliftTask[E] extends Unlift[Task, Env[E, *]] { def lift[A](fa: Task[A]): Env[E, A] = Env.fromTask(fa) diff --git a/higherKindCore/src/main/scala/tofu/higherKind/Function2K.scala b/higherKindCore/src/main/scala/tofu/higherKind/Function2K.scala index c11cadfd7..d4ba741da 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/Function2K.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/Function2K.scala @@ -1,7 +1,7 @@ package tofu.higherKind import cats.data.Tuple2K import cats.{FlatMap, ~>} -import tofu.syntax.functionK.funK +import tofu.syntax.functionk.funK import tofu.syntax.monadic._ trait Function2K[F[_], G[_], H[_]] { diff --git a/higherKindCore/src/main/scala/tofu/higherKind/Mid.scala b/higherKindCore/src/main/scala/tofu/higherKind/Mid.scala index 3f3b37f05..aa1b346c3 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/Mid.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/Mid.scala @@ -3,7 +3,7 @@ import cats.data.Chain import cats.tagless.ApplyK import cats.{Monoid, MonoidK, Semigroup} import tofu.higherKind.Mid.MidCompose -import tofu.syntax.functionK.funK +import tofu.syntax.functionk.funK import tofu.syntax.monoidalK._ trait Mid[F[_], A] { diff --git a/higherKindCore/src/main/scala/tofu/higherKind/Post.scala b/higherKindCore/src/main/scala/tofu/higherKind/Post.scala index 0d1ef7d60..80879cddb 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/Post.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/Post.scala @@ -1,7 +1,7 @@ package tofu.higherKind import cats.tagless.ApplyK import cats.{Applicative, Apply, FlatMap, Monoid, MonoidK, Semigroup, SemigroupK, ~>} -import tofu.syntax.functionK.funK +import tofu.syntax.functionk.funK import tofu.syntax.monadic._ /** diff --git a/higherKindCore/src/main/scala/tofu/higherKind/Pre.scala b/higherKindCore/src/main/scala/tofu/higherKind/Pre.scala index ab1a99c0d..64d213a18 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/Pre.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/Pre.scala @@ -2,7 +2,7 @@ package tofu package higherKind import cats.tagless.ApplyK import cats.{Applicative, Apply, Monoid, MonoidK, Semigroup, SemigroupK, ~>} -import tofu.syntax.functionK.funK +import tofu.syntax.functionk.funK import tofu.syntax.monadic._ /** diff --git a/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala b/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala index 05438ce36..7c1d00016 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala @@ -1,10 +1,9 @@ package tofu.higherKind -import cats.data.{EitherT, IorT, OptionT, ReaderT, Tuple2K, WriterT} -import cats.free.Cofree +import cats.data._ import cats.tagless.IdK import cats.{FlatMap, ~>} import simulacrum.typeclass -import tofu.syntax.functionK.funK +import tofu.syntax.functionk.funK import tofu.syntax.monadic._ trait RepK[U[_[_]], A] { diff --git a/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala b/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala index a1f1e2cb7..3729c44dc 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala @@ -22,7 +22,7 @@ class HigherKindedMacros(override val c: blackbox.Context) extends cats.tagless. val members = overridableMembersOf(af) val types = delegateAbstractTypes(af, members, af) val repk = reify(tofu.higherKind.RepK).tree - val funk = reify(tofu.syntax.functionK).tree + val funk = reify(tofu.syntax.functionk).tree val alg = TermName(c.freshName("alg")) val rep = TermName(c.freshName("rep")) val et = tq"" diff --git a/higherKindCore/src/main/scala/tofu/syntax/functionK.scala b/higherKindCore/src/main/scala/tofu/syntax/functionK.scala index 5f6c4019f..e63cf9d38 100644 --- a/higherKindCore/src/main/scala/tofu/syntax/functionK.scala +++ b/higherKindCore/src/main/scala/tofu/syntax/functionK.scala @@ -1,6 +1,7 @@ package tofu.syntax import cats.~> +@deprecated("use tofu.syntax.functionk._", since = "0.7.2") object functionK { /** simple constructor of FunctionK @@ -19,3 +20,34 @@ object functionK { type Arbitrary } + +object functionk { + + /** simple constructor of FunctionK + * you can use it as makeFunctionK[List, Option](_.headOption) + * credits : https://github.com/alexknvl*/ + def makeFunctionK[F[_], G[_]] = new Applied2[F, G](true) + + def funK[F[_], G[_]] = new Applied2[F, G](true) + + def funKFrom[F[_]] = new Applied1[F](true) + + final class Applied2[F[_], G[_]](private val __ : Boolean) extends AnyVal { + type Arbitrary + + def apply(maker: Maker[F, G, Arbitrary]): F ~> G = maker + } + + final class Applied1[F[_]](private val __ : Boolean) extends AnyVal { + type Arbitrary + + def apply[G[_]](maker: Maker[F, G, Arbitrary]): F ~> G = maker + } + + abstract class Maker[F[_], G[_], Arbitrary] extends (F ~> G) { + + def applyArbitrary(f: F[Arbitrary]): G[Arbitrary] + + def apply[A](fa: F[A]): G[A] = applyArbitrary(fa.asInstanceOf[F[Arbitrary]]).asInstanceOf[G[A]] + } +} diff --git a/zio/core/src/main/scala/tofu/zioInstances/ZioTofuInstance.scala b/zio/core/src/main/scala/tofu/zioInstances/ZioTofuInstance.scala index eede049ac..24f803355 100644 --- a/zio/core/src/main/scala/tofu/zioInstances/ZioTofuInstance.scala +++ b/zio/core/src/main/scala/tofu/zioInstances/ZioTofuInstance.scala @@ -8,7 +8,7 @@ import tofu.generate.GenRandom import tofu.internal.CachedMatcher import tofu.lift.Unlift import tofu.optics.{Contains, Extract} -import tofu.syntax.functionK.funK +import tofu.syntax.functionk.funK import tofu.zioInstances.ZioTofuInstance.convertFiber import zio.clock.Clock import zio.console.Console