Skip to main content

EitherT

Extension Methods for EitherT

import extras.cats.syntax.either._

or

import extras.cats.syntax.all._

eitherT / t for F[Either[A, B]]

When you have fab: F[Either[A, B]], instead of EitherT(fab), you can simply do

fab.eitherT // EitherT[F, A, B]
// or
fab.t // EitherT[F, A, B]
import cats.syntax.all._
import cats.effect._

import extras.cats.syntax.all._

val fab = IO.pure(1.asRight[String])
// fab: IO[Either[String, Int]] = Pure(a = Right(value = 1))
fab.t
// res1: cats.data.EitherT[IO, String, Int] = EitherT(
// value = Pure(a = Right(value = 1))
// )

val f = IO(println("Hello").asRight[String])
// f: IO[Either[String, Unit]] = Delay(
// thunk = <function0>,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO$.delay(IO.scala:1176),
// cats.effect.IO$.apply(IO.scala:1144),
// repl.MdocSession$App0$.<clinit>(eithert.md:26),
// repl.MdocSession$App.<init>(eithert.md:5),
// repl.MdocSession$.app(eithert.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.$anonfun$buildDocument$2(MarkdownBuilder.scala:47),
// mdoc.internal.markdown.MarkdownBuilder$$anon$1.run(MarkdownBuilder.scala:104)
// )
// )
// )
f.t
// res2: cats.data.EitherT[IO, String, Unit] = EitherT(
// value = Delay(
// thunk = <function0>,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO$.delay(IO.scala:1176),
// cats.effect.IO$.apply(IO.scala:1144),
// repl.MdocSession$App0$.<clinit>(eithert.md:26),
// repl.MdocSession$App.<init>(eithert.md:5),
// repl.MdocSession$.app(eithert.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.$anonfun$buildDocument$2(MarkdownBuilder.scala:47),
// mdoc.internal.markdown.MarkdownBuilder$$anon$1.run(MarkdownBuilder.scala:104)
// )
// )
// )
// )

eitherT / t for Either[A, B]

When you have ab: Either[A, B], instead of EitherT.fromEither[F](ab), you can simply do

ab.eitherT[F] // EitherT[F, A, B]
// or
ab.t[F] // EitherT[F, A, B]
import cats.syntax.all._
import cats.effect._

import extras.cats.syntax.all._

val ab = 1.asRight[String]
// ab: Either[String, Int] = Right(value = 1)
ab.t[IO]
// res4: cats.data.EitherT[IO, String, Int] = EitherT(
// value = Pure(a = Right(value = 1))
// )

rightT for F[B]

When you have fb: F[B], instead of EitherT.right[A](fb), you can simply do

fb.rightT[A] // EitherT[F, A, B]
import cats.effect._

import extras.cats.syntax.all._

val fb = IO.pure(1)
// fb: IO[Int] = Pure(a = 1)
fb.rightT[String]
// res6: cats.data.EitherT[IO, String, Int] = EitherT(
// value = Map(
// source = Pure(a = 1),
// f = cats.data.EitherT$RightPartiallyApplied$$$Lambda$8168/0x000000010237f040@1ade180f,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO.map(IO.scala:106),
// cats.effect.IOLowPriorityInstances$IOEffect.map(IO.scala:872),
// cats.effect.IOLowPriorityInstances$IOEffect.map(IO.scala:865),
// cats.data.EitherT$RightPartiallyApplied$.apply$extension(EitherT.scala:694),
// extras.cats.syntax.EitherSyntax$EitherTFAOps$.rightT$extension(EitherSyntax.scala:37),
// repl.MdocSession$App5$.<clinit>(eithert.md:68),
// repl.MdocSession$App3$.<clinit>(eithert.md:53),
// repl.MdocSession$App0$.<clinit>(eithert.md:32),
// repl.MdocSession$App.<init>(eithert.md:5),
// repl.MdocSession$.app(eithert.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.$anonfun$buildDocument$2(MarkdownBuilder.scala:47),
// mdoc.internal.markdown.MarkdownBuilder$$anon$1.run(MarkdownBuilder.scala:104)
// )
// )
// )
// )

val f = IO(println("Hello"))
// f: IO[Unit] = Delay(
// thunk = <function0>,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO$.delay(IO.scala:1176),
// cats.effect.IO$.apply(IO.scala:1144),
// repl.MdocSession$App5$.<clinit>(eithert.md:71),
// repl.MdocSession$App3$.<clinit>(eithert.md:53),
// repl.MdocSession$App0$.<clinit>(eithert.md:32),
// repl.MdocSession$App.<init>(eithert.md:5),
// repl.MdocSession$.app(eithert.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.$anonfun$buildDocument$2(MarkdownBuilder.scala:47),
// mdoc.internal.markdown.MarkdownBuilder$$anon$1.run(MarkdownBuilder.scala:104)
// )
// )
// )
f.rightT[String]
// res7: cats.data.EitherT[IO, String, Unit] = EitherT(
// value = Map(
// source = Delay(
// thunk = <function0>,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO$.delay(IO.scala:1176),
// cats.effect.IO$.apply(IO.scala:1144),
// repl.MdocSession$App5$.<clinit>(eithert.md:71),
// repl.MdocSession$App3$.<clinit>(eithert.md:53),
// repl.MdocSession$App0$.<clinit>(eithert.md:32),
// repl.MdocSession$App.<init>(eithert.md:5),
// repl.MdocSession$.app(eithert.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.$anonfun$buildDocument$2(MarkdownBuilder.scala:47),
// mdoc.internal.markdown.MarkdownBuilder$$anon$1.run(MarkdownBuilder.scala:104)
// )
// )
// ),
// f = cats.data.EitherT$RightPartiallyApplied$$$Lambda$8168/0x000000010237f040@1ade180f,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO.map(IO.scala:106),
// cats.effect.IOLowPriorityInstances$IOEffect.map(IO.scala:872),
// cats.effect.IOLowPriorityInstances$IOEffect.map(IO.scala:865),
// cats.data.EitherT$RightPartiallyApplied$.apply$extension(EitherT.scala:694),
// ...

leftT for F[A]

When you have fa: F[A], instead of EitherT.left[B](fa), you can simply do

fa.leftT[B] // EitherT[F, A, B]
import cats.effect._

import extras.cats.syntax.all._

val fa = IO.pure("ERROR!!!")
// fa: IO[String] = Pure(a = "ERROR!!!")
fa.leftT[Int]
// res9: cats.data.EitherT[IO, String, Int] = EitherT(
// value = Map(
// source = Pure(a = "ERROR!!!"),
// f = cats.data.EitherT$LeftPartiallyApplied$$$Lambda$8169/0x000000010237e040@138d6967,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO.map(IO.scala:106),
// cats.effect.IOLowPriorityInstances$IOEffect.map(IO.scala:872),
// cats.effect.IOLowPriorityInstances$IOEffect.map(IO.scala:865),
// cats.data.EitherT$LeftPartiallyApplied$.apply$extension(EitherT.scala:658),
// extras.cats.syntax.EitherSyntax$EitherTFAOps$.leftT$extension(EitherSyntax.scala:38),
// repl.MdocSession$App8$.<clinit>(eithert.md:92),
// repl.MdocSession$App5$.<clinit>(eithert.md:77),
// repl.MdocSession$App3$.<clinit>(eithert.md:53),
// repl.MdocSession$App0$.<clinit>(eithert.md:32),
// repl.MdocSession$App.<init>(eithert.md:5),
// repl.MdocSession$.app(eithert.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.$anonfun$buildDocument$2(MarkdownBuilder.scala:47),
// mdoc.internal.markdown.MarkdownBuilder$$anon$1.run(MarkdownBuilder.scala:104)
// )
// )
// )
// )

val f = IO(println("ERROR!!!"))
// f: IO[Unit] = Delay(
// thunk = <function0>,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO$.delay(IO.scala:1176),
// cats.effect.IO$.apply(IO.scala:1144),
// repl.MdocSession$App8$.<clinit>(eithert.md:95),
// repl.MdocSession$App5$.<clinit>(eithert.md:77),
// repl.MdocSession$App3$.<clinit>(eithert.md:53),
// repl.MdocSession$App0$.<clinit>(eithert.md:32),
// repl.MdocSession$App.<init>(eithert.md:5),
// repl.MdocSession$.app(eithert.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.$anonfun$buildDocument$2(MarkdownBuilder.scala:47),
// mdoc.internal.markdown.MarkdownBuilder$$anon$1.run(MarkdownBuilder.scala:104)
// )
// )
// )
f.leftT[Int]
// res10: cats.data.EitherT[IO, Unit, Int] = EitherT(
// value = Map(
// source = Delay(
// thunk = <function0>,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO$.delay(IO.scala:1176),
// cats.effect.IO$.apply(IO.scala:1144),
// repl.MdocSession$App8$.<clinit>(eithert.md:95),
// repl.MdocSession$App5$.<clinit>(eithert.md:77),
// repl.MdocSession$App3$.<clinit>(eithert.md:53),
// repl.MdocSession$App0$.<clinit>(eithert.md:32),
// repl.MdocSession$App.<init>(eithert.md:5),
// repl.MdocSession$.app(eithert.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.$anonfun$buildDocument$2(MarkdownBuilder.scala:47),
// mdoc.internal.markdown.MarkdownBuilder$$anon$1.run(MarkdownBuilder.scala:104)
// )
// )
// ),
// f = cats.data.EitherT$LeftPartiallyApplied$$$Lambda$8169/0x000000010237e040@138d6967,
// trace = StackTrace(
// stackTrace = List(
// cats.effect.internals.IOTracing$.buildFrame(IOTracing.scala:48),
// cats.effect.internals.IOTracing$.buildCachedFrame(IOTracing.scala:39),
// cats.effect.internals.IOTracing$.cached(IOTracing.scala:34),
// cats.effect.IO.map(IO.scala:106),
// cats.effect.IOLowPriorityInstances$IOEffect.map(IO.scala:872),
// cats.effect.IOLowPriorityInstances$IOEffect.map(IO.scala:865),
// cats.data.EitherT$LeftPartiallyApplied$.apply$extension(EitherT.scala:65...

Example

import cats.syntax.all._
import cats.effect._

import extras.cats.syntax.all._

final case class MyError(message: String)

def foo[F[_]: Sync](n: Int): F[Int] = Sync[F].pure(n * 2)

def bar[F[_]: Sync](n: Int): F[Either[MyError, Int]] =
if (n < 0)
Sync[F].pure(MyError(s"n cannot be a negative number. [n: $n]").asLeft)
else
Sync[F].pure((n + 100).asRight)

def divide[F[_]: Sync](a: Int, b: Int): F[Either[MyError, Int]] =
if (b == 0)
MyError(s"You can divide number by 0. [a: $a, b: $b]").asLeft.pure[F]
else
Sync[F].delay((a / b).asRight)

def run[F[_]: Sync](): F[Either[MyError, Int]] = (for {
a <- foo(123).rightT
b <- 2.rightTF[F, MyError]
c <- bar(b).eitherT
d <- divide(a, b).t
} yield d).value

println(run[IO]().unsafeRunSync())
// Right(123)