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.
Today Traverse was not the answer; it was Foldable
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 then one type parameter
object Fs {
type Either_[A] = Either[Throwable, A]
}
import Fs._
///
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(
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[F[_]: Monad](value: String, version: Int): F[Int] = {
// pretend I'm doing something with the `value`
// and returning an updated version
(version + 1).pure
}
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>")
new IllegalStateException("Frunfles must have a value").raiseError
} else {
println(s">>> ${frunfles.value}")
doStuff(frunfles.value, version)
}
}
}
///
// Change the effect and the list in `f[...]`
val out = f[IO](badList, 1).run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment