Skip to main content
Version: v2.1.0

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.

import effectie.core._
import effectie.syntax.all._

def foo[F[_]: Fx]: F[Int] = pureOf(1)
import cats.effect._
import effectie.syntax.all._

import effectie.instances.ce3.fx.ioFx

pureOf[IO](1)
// res3: IO[Int] = Pure(value = 1)

effectOf

To construct F[A] for an operation with referential transparency, you can use effectOf.

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 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
// )

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.
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 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
// )

unitOf

If you just return F[Unit], you can use unitOf.

e.g.)

unitOf[IO] // IO[Unit]
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.effect._
import effectie.syntax.all._

import effectie.instances.ce3.fx.ioFx

unitOf[IO]
// res27: IO[Unit] = Pure(value = ())

Example

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
// )