Fx
If you use Cats Effect and write tagless final code, and look for a generic way to construct F[A], Fx can help you.
pureOf
To construct F[A] for a pure value A, you can use pureOf.
- with syntax
- without syntax
import effectie.core._
import effectie.syntax.all._
def foo[F[_]: Fx]: F[Int] = pureOf(1)
import effectie.core._
def foo[F[_]: Fx]: F[Int] = Fx[F].pureOf(1)
- with syntax
- without syntax
import cats.effect._
import effectie.syntax.all._
import effectie.instances.ce3.fx.ioFx
pureOf[IO](1)
// res3: IO[Int] = Pure(value = 1)
import cats.effect._
import effectie.core._
import effectie.instances.ce3.fx.ioFx
Fx[IO].pureOf(1)
// res5: IO[Int] = Pure(value = 1)
effectOf
To construct F[A] for an operation with referential transparency, you can use effectOf.
- with syntax
- without syntax
import effectie.core._
import effectie.syntax.all._
def foo[F[_]: Fx](): F[Unit] = effectOf(println("Hello"))
import cats.effect._
import effectie.instances.ce3.fx.ioFx
(for {
_ <- foo[IO]()
_ <- foo[IO]()
_ <- foo[IO]()
} yield ())
// res7: IO[Unit] = FlatMap(
// ioe = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// ),
// f = <function1>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
import effectie.core._
def foo[F[_]: Fx](): F[Unit] = Fx[F].effectOf(println("Hello"))
import cats.effect._
import effectie.instances.ce3.fx.ioFx
(for {
_ <- foo[IO]()
_ <- foo[IO]()
_ <- foo[IO]()
} yield ())
// res9: IO[Unit] = FlatMap(
// ioe = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// ),
// f = <function1>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
- with syntax
- without syntax
import cats.effect._
import effectie.syntax.all._
import effectie.instances.ce3.fx.ioFx
effectOf[IO](println("Hello"))
// res11: IO[Unit] = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
// effectOf can handle exception properly.
effectOf[IO][Int](throw new RuntimeException("ERROR"))
// res12: IO[Int] = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
import cats.effect._
import effectie.core._
import effectie.instances.ce3.fx.ioFx
Fx[IO].effectOf(println("Hello"))
// res14: IO[Unit] = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
// effectOf can handle exception properly.
Fx[IO].effectOf[Int](throw new RuntimeException("ERROR"))
// res15: IO[Int] = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
pureOrError
To construct F[A] for a pure value, but it can also throw an exception, you can use pureOrError instead of effectOf.
If an expression returns a pure value, and it's always the same so there's no point in using effectOf for referential transparency, you can use pureOf. However, if that expression can also throw an exception, pureOf cannot handle it properly. In this case, pureOrError is the right one.
e.g.)
val s: String = "abc"
pureOf[IO](s.substring(5))
// This immediately throws a StringIndexOutOfBoundsException even though F[_] here is IO.
val s: String = "abc"
pureOrError[IO](s.substring(5))
// StringIndexOutOfBoundsException is now captured by IO.
- with syntax
- without syntax
import effectie.core._
import effectie.syntax.all._
def foo[F[_]: Fx]: F[Int] = pureOrError(1)
def bar[F[_]: Fx](s: String): F[String] = pureOrError(s.substring(5))
import effectie.core._
def foo[F[_]: Fx]: F[Int] = Fx[F].pureOrError(1)
def bar[F[_]: Fx](s: String): F[String] = Fx[F].pureOrError(s.substring(5))
- with syntax
- without syntax
import cats.effect._
import effectie.syntax.all._
import effectie.instances.ce3.fx.ioFx
pureOrError[IO](1)
// res19: IO[Int] = Pure(value = 1)
pureOrError[IO]("abc".substring(5))
// res20: IO[String] = Error(
// t = java.lang.StringIndexOutOfBoundsException: String index out of range: -2
// )
import cats.effect._
import effectie.core._
import effectie.instances.ce3.fx.ioFx
Fx[IO].pureOrError(1)
// res22: IO[Int] = Pure(value = 1)
Fx[IO].pureOrError("abc".substring(5))
// res23: IO[String] = Error(
// t = java.lang.StringIndexOutOfBoundsException: String index out of range: -2
// )
unitOf
If you just return F[Unit], you can use unitOf.
e.g.)
unitOf[IO] // IO[Unit]
- with syntax
- without syntax
import cats._
import cats.syntax.all._
import effectie.core._
import effectie.syntax.all._
def foo[F[_]: Fx]: F[Unit] = unitOf
def bar[F[_]: Fx: Monad]: F[Unit] =
effectOf(println("Hello")) *> unitOf // You can do effectOf(println("Hello")).void instead
import cats._
import cats.syntax.all._
import effectie.core._
def foo[F[_]: Fx]: F[Unit] = Fx[F].unitOf
def bar[F[_]: Fx: Monad]: F[Unit] =
Fx[F].effectOf(println("Hello")) *> Fx[F].unitOf // You can do Fx[F].effectOf(println("Hello")).void instead
- with syntax
- without syntax
import cats.effect._
import effectie.syntax.all._
import effectie.instances.ce3.fx.ioFx
unitOf[IO]
// res27: IO[Unit] = Pure(value = ())
import cats.effect._
import effectie.core._
import effectie.instances.ce3.fx.ioFx
Fx[IO].unitOf
// res29: IO[Unit] = Pure(value = ())
Example
- with syntax
- without syntax
import effectie.core._
import effectie.syntax.all._
trait Something[F[_]] {
def get[A](a: => A): F[A]
}
object Something {
def apply[F[_]: Something]: Something[F] =
implicitly[Something[F]]
implicit def something[F[_]: Fx]: Something[F] =
new SomethingF[F]
final class SomethingF[F[_]: Fx]
extends Something[F] {
def get[A](a: => A): F[A] =
effectOf(a)
// No more Fx[F].effectOf(a)
}
}
import cats.effect._
import effectie.instances.ce3.fx.ioFx
val get1 = Something[IO].get(1)
// get1: IO[Int] = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
get1
// res31: IO[Int] = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
import effectie.core._
trait Something[F[_]] {
def get[A](a: => A): F[A]
}
object Something {
def apply[F[_]: Something]: Something[F] =
implicitly[Something[F]]
implicit def something[F[_]: Fx]: Something[F] =
new SomethingF[F]
final class SomethingF[F[_]: Fx]
extends Something[F] {
def get[A](a: => A): F[A] =
Fx[F].effectOf(a)
}
}
import cats.effect._
import effectie.instances.ce3.fx.ioFx
val get1 = Something[IO].get(1)
// get1: IO[Int] = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
get1
// res33: IO[Int] = Delay(
// thunk = <function0>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )