Skip to content

Instantly share code, notes, and snippets.

@programaker
Last active October 21, 2021 14:48
Show Gist options
  • Save programaker/b9246c4e2e8e40a519986765d2ab316f to your computer and use it in GitHub Desktop.
Save programaker/b9246c4e2e8e40a519986765d2ab316f to your computer and use it in GitHub Desktop.

Revisions

  1. programaker revised this gist Oct 21, 2021. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions foldLeftM.scala
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,12 @@
    import cats.effect.IO
    import cats.syntax.foldable._
    import cats.syntax.applicative._
    import cats.syntax.applicativeError._
    import cats.{ApplicativeThrow, Monad}

    import scala.util.Try

    // Stores type aliases for effects that have more than one type parameter
    // Stores type aliases for effects that have more then one type parameter
    object Fs {
    type Either_[A] = Either[Throwable, A]
    }
    @@ -66,7 +68,7 @@ val badList = List(
    def doStuff[F[_]: Monad](value: String, version: Int): F[Int] = {
    // pretend I'm doing something with the `value`
    // and returning an updated version
    Monad[F].pure(version + 1)
    (version + 1).pure
    }

    def f[F[_]: Monad: ApplicativeThrow](allFrunfles: List[Frunfles], startVersion: Int): F[Int] = {
    @@ -75,7 +77,7 @@ def f[F[_]: Monad: ApplicativeThrow](allFrunfles: List[Frunfles], startVersion:
    allFrunfles.foldLeftM(startVersion) { (version, frunfles) =>
    if (frunfles.value.isBlank) {
    println(">>> <blank>")
    ApplicativeThrow[F].raiseError(new IllegalStateException("Frunfles must have a value"))
    new IllegalStateException("Frunfles must have a value").raiseError
    } else {
    println(s">>> ${frunfles.value}")
    doStuff(frunfles.value, version)
    @@ -86,5 +88,4 @@ def f[F[_]: Monad: ApplicativeThrow](allFrunfles: List[Frunfles], startVersion:
    ///

    // Change the effect and the list in `f[...]`
    // Currently available: IO, Either_, Try
    val out = f[IO](badList, 1).run()
  2. programaker revised this gist Oct 5, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion foldLeftM.scala
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ import cats.{ApplicativeThrow, Monad}

    import scala.util.Try

    // Stores type aliases for effects that have more then one type parameter
    // Stores type aliases for effects that have more than one type parameter
    object Fs {
    type Either_[A] = Either[Throwable, A]
    }
  3. programaker revised this gist Sep 29, 2021. 1 changed file with 49 additions and 26 deletions.
    75 changes: 49 additions & 26 deletions foldLeftM.scala
    Original file line number Diff line number Diff line change
    @@ -1,30 +1,45 @@
    import cats.effect.IO
    import cats.syntax.foldable._
    import cats.{ApplicativeThrow, Monad}

    // Modify the commented sections below to change the Effect (as long as the Effect has a Monad)
    import scala.util.Try

    /*type Eff[A] = Either[Throwable, A]
    object Eff {
    def success[A](a: A): Eff[A] = Right(a)
    def error[A](e: Throwable): Eff[A] = Left(e)
    def run[A](eff: Eff[A]): A = eff.getOrElse(throw _)
    }*/
    // Stores type aliases for effects that have more then one type parameter
    object Fs {
    type Either_[A] = Either[Throwable, A]
    }
    import Fs._

    /*type Eff[A] = Option[A]
    object Eff {
    def success[A](a: A): Eff[A] = Some(a)
    def error[A](e: Throwable): Eff[A] = None
    def run[A](eff: Eff[A]): A = eff.get
    }*/
    ///

    import cats.effect.IO
    import cats.effect.unsafe.implicits.global
    type Eff[A] = IO[A]
    object Eff {
    def success[A](a: A): Eff[A] = IO.pure(a)
    def error[A](e: Throwable): Eff[A] = IO.raiseError(e)
    def run[A](eff: Eff[A]): A = eff.unsafeRunSync()
    trait Interpreter[F[_]] {
    def run[A](fa: F[A]): A
    }
    object Interpreter {
    def apply[F[_]](implicit I: Interpreter[F]): Interpreter[F] = I

    implicit val eitherInterpreter: Interpreter[Either_] = new Interpreter[Either_] {
    override def run[A](fa: Either_[A]): A = fa match {
    case Left(e) => throw e
    case Right(a) => a
    }
    }

    import cats.effect.unsafe.implicits.global
    implicit val ioInterpreter: Interpreter[IO] = new Interpreter[IO] {
    override def run[A](fa: IO[A]): A = fa.unsafeRunSync()
    }

    implicit val tryInterpreter: Interpreter[Try] = new Interpreter[Try] {
    override def run[A](fa: Try[A]): A = fa.get
    }
    }
    implicit class InterpreterSyntax[F[_]: Interpreter, A](fa: F[A]) {
    def run(): A = Interpreter[F].run(fa)
    }

    ///

    final case class Frunfles(value: String)

    val goodList = List(
    @@ -46,22 +61,30 @@ val badList = List(
    Frunfles("Z"),
    )

    def doStuff(value: String, version: Int): Eff[Int] = {
    ///

    def doStuff[F[_]: Monad](value: String, version: Int): F[Int] = {
    // pretend I'm doing something with the `value`
    // and returning an updated version
    Eff.success(version + 1)
    Monad[F].pure(version + 1)
    }

    def f(allFrunfles: List[Frunfles], startVersion: Int): Eff[Int] =
    def f[F[_]: Monad: ApplicativeThrow](allFrunfles: List[Frunfles], startVersion: Int): F[Int] = {
    // `foldLeftM` works with any `F[_]` as long as a `Monad` instance exists for it! =D
    // It breaks the folding loop if an error happens - if the Monad instance has some "error" semantic
    allFrunfles.foldLeftM(startVersion) { (version, frunfles) =>
    if (frunfles.value.isBlank) {
    println(">>> <blank>")
    Eff.error(new IllegalStateException("Frunfles must have a value"))
    ApplicativeThrow[F].raiseError(new IllegalStateException("Frunfles must have a value"))
    } else {
    println(s">>> ${frunfles.value}")
    doStuff(frunfles.value, version)
    }
    }
    }

    ///

    val out = Eff.run(f(goodList, 1))
    //val out2 = Eff.run(f(badList, 1))
    // Change the effect and the list in `f[...]`
    // Currently available: IO, Either_, Try
    val out = f[IO](badList, 1).run()
  4. programaker created this gist Sep 3, 2021.
    67 changes: 67 additions & 0 deletions foldLeftM.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    import cats.syntax.foldable._

    // Modify the commented sections below to change the Effect (as long as the Effect has a Monad)

    /*type Eff[A] = Either[Throwable, A]
    object Eff {
    def success[A](a: A): Eff[A] = Right(a)
    def error[A](e: Throwable): Eff[A] = Left(e)
    def run[A](eff: Eff[A]): A = eff.getOrElse(throw _)
    }*/

    /*type Eff[A] = Option[A]
    object Eff {
    def success[A](a: A): Eff[A] = Some(a)
    def error[A](e: Throwable): Eff[A] = None
    def run[A](eff: Eff[A]): A = eff.get
    }*/

    import cats.effect.IO
    import cats.effect.unsafe.implicits.global
    type Eff[A] = IO[A]
    object Eff {
    def success[A](a: A): Eff[A] = IO.pure(a)
    def error[A](e: Throwable): Eff[A] = IO.raiseError(e)
    def run[A](eff: Eff[A]): A = eff.unsafeRunSync()
    }

    final case class Frunfles(value: String)

    val goodList = List(
    Frunfles("A"),
    Frunfles("B"),
    Frunfles("C"),
    Frunfles("X"),
    Frunfles("Y"),
    Frunfles("Z"),
    )

    val badList = List(
    Frunfles("A"),
    Frunfles("B"),
    Frunfles("C"),
    Frunfles(""), //<- a bad Frunfles among us!
    Frunfles("X"),
    Frunfles("Y"),
    Frunfles("Z"),
    )

    def doStuff(value: String, version: Int): Eff[Int] = {
    // pretend I'm doing something with the `value`
    // and returning an updated version
    Eff.success(version + 1)
    }

    def f(allFrunfles: List[Frunfles], startVersion: Int): Eff[Int] =
    allFrunfles.foldLeftM(startVersion) { (version, frunfles) =>
    if (frunfles.value.isBlank) {
    println(">>> <blank>")
    Eff.error(new IllegalStateException("Frunfles must have a value"))
    } else {
    println(s">>> ${frunfles.value}")
    doStuff(frunfles.value, version)
    }
    }

    val out = Eff.run(f(goodList, 1))
    //val out2 = Eff.run(f(badList, 1))