Skip to content

Instantly share code, notes, and snippets.

@butcherless
Last active December 2, 2020 09:34
Show Gist options
  • Save butcherless/b475c4b82b12e9a76059c79a25eac7f2 to your computer and use it in GitHub Desktop.
Save butcherless/b475c4b82b12e9a76059c79a25eac7f2 to your computer and use it in GitHub Desktop.
Never ever write a loop
/* live demo ZIO.loop
https://scastie.scala-lang.org/butcherless/IEXLzpbZSL28zmFK166IKA/2
*/
package com.cmartin.utils
import zio.{App, ExitCode, UIO, ZIO}
object ZioLoopDemo extends App {
import zio.console._
/**
* Loops with the specified effectual function, collecting the results into a
* list. The moral equivalent of:
*
* {{{
* var s = initial
* var as = List.empty[A]
*
* while (cont(s)) {
* as = body(s) :: as
* s = inc(s)
* }
*
* as.reverse
* }}}
*
* def loop[R, E, A, S](initial: S)(cont: S => Boolean, inc: S => S)(body: S => ZIO[R, E, A]): ZIO[R, E, List[A]] =
* if (cont(initial))
* body(initial).flatMap(a => loop(inc(initial))(cont, inc)(body).map(as => a :: as))
* else
* ZIO.succeedNow(List.empty[A])
*/
/*
* concepts
*/
/*
* result container
*/
case class MyResult(a: Double, text: String)
case class MyInfo(a: Int)
/*
* initial state of the business information
*/
val initial: MyInfo = MyInfo(10)
/*
* function that determines the continuation of the processing loop
*/
def cont(info: MyInfo): Boolean = info.a > 0
/*
* function that gets the next status of business information
*/
def dec(info: MyInfo): MyInfo = MyInfo(info.a - 1)
/*
* business function
*/
def body(info: MyInfo): UIO[MyResult] =
UIO(MyResult(info.a.toDouble, intTypeText(info.a)))
/*
* helper functions
*/
def intTypeText(a: Int) = if (a % 2 == 0) "even" else "odd"
def prettyPrint[A](l: List[A]): String = l.mkString("\n\t", "\n\t", "\n")
/*
* program
*/
val program = for {
_ <- putStrLn("zio loop demo:")
evenOrOddList <- ZIO.loop(initial)(cont, dec)(body)
_ <- putStrLn(s"-> evenOrOddList => ${prettyPrint(evenOrOddList)}")
} yield ()
// main function, needs exit = 0 [OK] or exit > 0 [ERROR]
// Here the interpreter runs the program and perform side-effects
override def run(args: List[String]): ZIO[zio.ZEnv, Nothing, ExitCode] = {
(program as ExitCode.success)
.catchAllCause(cause => putStrLn(s"${cause.prettyPrint}") as ExitCode.failure)
}
}
@butcherless
Copy link
Author

butcherless commented Sep 3, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment