Either

The Either effect is similar to the Option effect but adds the possibility to specify why a computation stopped:

import org.atnos.eff._, all._, syntax.all._

  /**
   * Stack declaration
   */
  type S = Fx.fx1[String Either ?]

  // compute with this stack
  val map: Map[String, Int] =
    Map("key1" -> 10, "key2" -> 20)

  // get 2 keys from the map and add the corresponding values
  def addKeys(key1: String, key2: String): Eff[S, Int] = for {
    a <- optionEither(map.get(key1), s"'$key1' not found")
    b <- optionEither(map.get(key2), s"'$key2' not found")
  } yield a + b

  (addKeys("key1", "key2").runEither.run, addKeys("key1", "missing").runEither.run)

> (Right(30),Left('missing' not found))

Note: the ? syntax comes from the kind-projector project and allows us to avoid type lambdas.

A catchLeft method can also be used to intercept an error and possibly recover from it:

  case class TooBig(value: Int)
  type E = Fx.fx1[TooBig Either ?]

  val i = 7

  val value: Eff[E, Int] =
    if (i > 5) left[E, TooBig, Int](TooBig(i))
    else       right[E, TooBig, Int](i)

  val action: Eff[E, Int] = catchLeft[E, TooBig, Int](value) { case TooBig(k) =>
    if (k < 10) right[E, TooBig, Int](k)
    else        left[E, TooBig, Int](TooBig(k))
  }

  action.runEither.run ==== Right(7)

Note: the type annotations on left and right can be avoided by adding an implicit declaration in scope. You can learn more about this in the Implicits section.