Skip to main content
Version: v2.5.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.ce2.fx.ioFx

pureOf[IO](1)
// res3: IO[Int] = Pure(a = 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.ce2.fx.ioFx

(for {
_ <- foo[IO]()
_ <- foo[IO]()
_ <- foo[IO]()
} yield ()).unsafeRunSync()
// Hello
// Hello
// Hello
import cats.effect._
import effectie.syntax.all._

import effectie.instances.ce2.fx.ioFx

effectOf[IO](println("Hello"))
// res11: IO[Unit] = Delay(
// thunk = <function0>,
// trace = StackTrace(
// ...

// effectOf can handle exception properly.
effectOf[IO][Int](throw new RuntimeException("ERROR"))
// res12: IO[Int] = Delay(
// thunk = <function0>,
// trace = 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.ce2.fx.ioFx

pureOrError[IO](1)
// res19: IO[Int] = Pure(a = 1)

pureOrError[IO]("abc".substring(5))
// res20: IO[String] = RaiseError(
// e = 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.ce2.fx.ioFx

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

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.ce2.fx.ioFx

val get1 = Something[IO].get(1)
// get1: IO[Int] = Delay(
// thunk = <function0>,
// trace = StackTrace(
// ...

get1.unsafeRunSync()
// res31: Int = 1