Skip to content

Instantly share code, notes, and snippets.

@zckkte
Created March 14, 2022 11:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zckkte/40f01436a8f2bd58e0905f0e09ba4421 to your computer and use it in GitHub Desktop.
Save zckkte/40f01436a8f2bd58e0905f0e09ba4421 to your computer and use it in GitHub Desktop.
Toy functional effect system
object Console {
def putStrLn(str: => String) = TIO.effect(println(str))
}
object FailAndRecover extends TIOApp {
def run = {
(for {
_ <- putStrLn("running first effect")
_ <- TIO.fail(new RuntimeException)
_ <- putStrLn("second effect - will not run")
} yield ()).recover {
case NonFatal(e) =>
putStrLn(s"recovered from failure: ${e.getClass.getName}")
}
}
}
import scala.util._
trait Runtime {
def unsafeRunSync[A](tio: TIO[A]): Try[A]
}
object Runtime extends Runtime {
def unsafeRunSync[A](tio: TIO[A]): Try[A] = eval(tio)
private def eval[A](tio: TIO[A]): Try[A] = {
tio match {
case TIO.Effect(a) =>
Try(a())
case TIO.FlatMap(tio, f: (Any => TIO[Any])) =>
eval[Any](tio) match {
case Success(res) => eval(f(res))
case Failure(e) => Failure(e)
}
case TIO.Fail(t) =>
Failure(t)
case TIO.Recover(tio, f) =>
eval(tio) match {
case Failure(e) => eval(f(e))
case success => success
}
}
}
}
package example
sealed trait TIO[+A] {
def flatMap[B](f: A => TIO[B]): TIO[B] = TIO.FlatMap(this, f)
def map[B](f: A => B): TIO[B] = flatMap(a => TIO.succeed(f(a)))
def recover[B >: A](f: Throwable => TIO[B]): TIO[B] = TIO.Recover(this, f)
def *>[B](that: TIO[B]): TIO[B] = flatMap(_ => that)
}
object TIO {
case class Effect[+A](a: () => A) extends TIO[A]
case class FlatMap[A, B](tio: TIO[A], f: A => TIO[B]) extends TIO[B]
case class Fail[A](e: Throwable) extends TIO[A]
case class Recover[A](tio: TIO[A], f: Throwable => TIO[A]) extends TIO[A]
def succeed[A](a: A): TIO[A] = Effect(() => a)
def effect[A](a: => A): TIO[A] = Effect(() => a)
def fail[A](throwable: Throwable): TIO[A] = Fail(throwable)
}
trait TIOApp {
def run: TIO[Any]
final def main(args: Array[String]): Unit = Runtime.unsafeRunSync(run).get
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment