Skip to content

Instantly share code, notes, and snippets.

@jdegoes
Last active May 24, 2021 19:31
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jdegoes/a799c7365d877da1face69dd139466de to your computer and use it in GitHub Desktop.
ZIO Workshop - Sky
package net.degoes.zio
import zio._
import java.io.IOException
import scala.annotation.tailrec
import scala.concurrent.ExecutionContext
trait Helpers {
implicit class ZIOExtensions[R, E, A](zio: ZIO[R, E, A]) {
val exited: ZIO[R, Nothing, Int] = zio.fold(_ => 1, _ => 0)
}
}
object App1 extends App with Helpers {
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
UIO(println("Hello World!")).exited
}
object App2 extends App with Helpers {
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
_ <- Task(println("What is your name?"))
name <- Task(scala.io.StdIn.readLine())
_ <- Task(println(s"Hello, ${name}, good to meet you!"))
} yield name).exited
}
object App3 extends App with Helpers {
import zio.console._
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStrLn(s"Hello, ${name}, good to meet you!")
} yield name).exited
}
object App4 extends App with Helpers {
import zio.console._
import zio.random._
def parseInt(string: String): Option[Int] =
scala.util.Try(string.toInt).toOption
def parseIntM(string: String): IO[Unit, Int] =
ZIO.fromOption(parseInt(string))
val getIntegerGuess =
getStrLn.flatMap(parseIntM(_)).tapError(_ => putStrLn("You did not enter a number!"))
def gameLoop(rand: Int): ZIO[Console, IOException, Unit] =
for {
_ <- putStrLn("Guess a number between 0 and 10:")
guess <- getIntegerGuess.eventually
_ <- if (guess == rand)
putStrLn("Congratulations, you guessed the correct number!")
else
putStrLn("Uh oh, you did not guess correctly. Keep trying!") *>
gameLoop(rand)
} yield ()
def run(args: List[String]): ZIO[Console with Random, Nothing, Int] =
(for {
_ <- putStrLn("Welcome to Number Guessing Game!")
rand <- nextInt(10)
_ <- gameLoop(rand)
} yield ()).exited
}
object App5 extends App with Helpers {
import java.util.concurrent.TimeUnit
import java.util.concurrent.ScheduledThreadPoolExecutor
private[this] val scheduler = new ScheduledThreadPoolExecutor(1)
def putStrLn(line: String): UIO[Unit] = ZIO.effectTotal(println(line))
val getStrLn: Task[String] = ZIO.effect(scala.io.StdIn.readLine())
val nextDouble: UIO[Double] = UIO(scala.util.Random.nextDouble)
def sleep(n: Long, unit: TimeUnit): UIO[Unit] =
UIO.effectAsync[Unit] { callback =>
scheduler.schedule(
new Runnable {
def run = callback(UIO.unit)
}, n, unit
)
}
def run(args: List[String]): UIO[Int] =
(for {
double <- nextDouble
millis <- ZIO.succeed((double * 1000.0).toLong)
_ <- putStrLn(s"About to sleep for ${millis} milliseconds")
_ <- sleep(millis, TimeUnit.MILLISECONDS)
_ <- putStrLn(s"Slept for ${millis} milliseconds")
_ <- putStrLn("How long would YOU like to sleep for, in seconds?")
time <- getStrLn.flatMap(string => Task(string.toDouble).tapError(_ =>
putStrLn("Please enter a double!"))).eventually
_ <- putStrLn(s"About to sleep for ${time} seconds")
_ <- sleep((time * 1000.0).toLong, TimeUnit.MILLISECONDS)
_ <- putStrLn(s"Slept for ${time} seconds")
_ <- UIO(scheduler.shutdown())
} yield ()).exited
}
object App8 extends App with Helpers {
import zio.console._
import zio.blocking.{ Blocking, effectBlocking }
import java.io._
final case class Input private (private val is: InputStream) {
val close: IO[IOException, Unit] =
IO(is.close()).refineToOrDie[IOException]
final def read(bufferSize: Int = 1024): ZIO[Blocking, IOException, Option[Chunk[Byte]]] =
effectBlocking {
val array = Array.ofDim[Byte](bufferSize)
val bytesRead = is.read(array)
if (bytesRead == -1) None
else Some(Chunk.fromArray(array).take(bytesRead))
}.refineToOrDie[IOException]
}
object Input {
final def open(file: File): IO[IOException, Input] =
IO(new Input(new FileInputStream(file))).refineToOrDie[IOException]
}
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(args match {
case Nil => putStrLn("Usage: App8 <file>")
case file :: _ =>
val fileResource = Managed.make(Input.open(new File(file)))(_.close.ignore)
fileResource.use { input =>
(input.read().mapError(Some(_)).flatMap {
case None => IO.fail(None)
case Some(chunk) =>
putStr(chunk.map(_.toChar).mkString("", "", ""))
}).forever orElse IO.unit
}
}).exited
}
object App9 extends App with Helpers {
import zio.console._
final def fib(n: BigInt): UIO[BigInt] =
if (n <= 1) UIO(n)
else (fib(n - 2) zipWith fib(n - 1))(_ + _)
val getNumber =
getStrLn.flatMap(line => Task(line.toInt)).tapError(_ =>
putStrLn("You did not enter a number!")
).eventually
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
_ <- putStrLn("How many fibonacci numbers would you like to compute in parallel?")
n <- getNumber
fibers <- ZIO.foreach(0 until n) { i =>
for {
_ <- putStrLn(s"Please enter fibonacci number ${i + 1} to compute:")
n <- getNumber
fiber <- fib(n).fork
} yield fiber
}
_ <- fibers.zipWithIndex.foldLeft[ZIO[Console, Nothing, Unit]](IO.unit) {
case (acc, (fiber, index)) =>
acc *> (for {
value <- fiber.join
_ <- putStrLn(s"The ${index + 1} fibonnaci result is ${value}")
} yield ())
}
} yield ()).exited
}
object App10 extends App with Helpers {
import zio.console._
import zio.duration._
final def fib(n: BigInt): UIO[BigInt] =
if (n <= 1) UIO(n)
else fib(n - 2).zipWith(fib(n - 1))(_ + _)
val getNumber =
getStrLn.flatMap(line => Task(line.toInt)).tapError(_ =>
putStrLn("You did not enter a number!")
).eventually
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
_ <- putStrLn("How many fibonacci numbers would you like to compute in parallel?")
n <- getNumber
nums <- ZIO.foreach(0 until n) { i =>
putStrLn(s"Please enter fibonacci number ${i + 1} to compute:") *>
getNumber
}
fibs <- ZIO.foreachPar(nums.zipWithIndex) {
case (num, index) =>
fib(num).tap(num =>
putStrLn(s"The ${index + 1} fibonnaci result is ${num}")
)
}.timeout(5.seconds)
_ <- putStrLn(s"The fibonacci numbers in order: ${fibs}")
} yield ()).exited
}
object App11 extends App with Helpers {
import zio.console._
sealed trait Command
object Command {
final case class ComputeFib(n: Int) extends Command
case object Quit extends Command
def fromString(s: String): Option[Command] = {
def extractFib(value: String): Option[Command] =
scala.util.Try(value.toInt).toOption.map(ComputeFib(_))
s.trim.toLowerCase match {
case "quit" | "exit" => Some(Quit)
case fib if (fib.startsWith("fib ")) => extractFib(fib.drop(3).trim)
case value => extractFib(value)
}
}
}
final def fib(n: BigInt): UIO[BigInt] =
if (n <= 1) UIO(n)
else fib(n - 2).zipWith(fib(n - 1))(_ + _)
val promptCommand: ZIO[Console, Nothing, Command] =
putStrLn("Please enter 'quit' or 'fib <n>':") *>
getStrLn.flatMap(line => IO.fromOption(Command.fromString(line)))
.tapError(_ => putStrLn("You did not enter either 'quit' or 'fib <n>'"))
.eventually
val getNumber =
getStrLn.flatMap(line => Task(line.toInt)).tapError(_ =>
putStrLn("You did not enter a number!")
).eventually
def makeWorker(queue: Queue[Int]) =
(for {
n <- queue.take
num <- fib(n)
_ <- putStrLn(s"Fibonacci number ${n} is ${num}")
} yield ()).forever
def forkAll[R, E, A](list: List[ZIO[R, E, A]]): ZIO[R, Nothing, Unit] =
list match {
case Nil => ZIO.unit
case z :: zs =>
for {
_ <- z.fork
_ <- forkAll(zs)
} yield ()
}
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
_ <- putStrLn("How many fibers would you like to use to compute fibonacci numbers?")
n <- getNumber
queue <- Queue.bounded[Int](100)
_ <- forkAll(List.fill(n)(makeWorker(queue)))
_ <- promptCommand.flatMap {
case Command.Quit => ZIO.fail(())
case Command.ComputeFib(n) => queue.offer(n)
}.forever.ignore
} yield ()).exited
}
object App12 extends App with Helpers {
import zio.console._
sealed trait ShellCommand
object ShellCommand {
final case class Ls(path: Option[String]) extends ShellCommand
final case class Cd(path: String) extends ShellCommand
case object Pwd extends ShellCommand
case object Quit extends ShellCommand
def fromString(input: String): Either[String, ShellCommand] =
input.trim match {
case x if x.toLowerCase == "ls" => Right(Ls(None))
case x if x.toLowerCase startsWith "ls " => Right(Ls(Some(x.drop(3))))
case x if x.toLowerCase startsWith "cd " => Right(Cd(x.drop(3)))
case x if x.toLowerCase == "pwd" => Right(Pwd)
case x if x.toLowerCase == "quit" => Right(Quit)
case x if x.toLowerCase == "exit" => Right(Quit)
case _ => Left("Expected command but received: " + input)
}
}
import ShellCommand._
import java.io.File
lazy val userCommand: ZIO[Console, Nothing, ShellCommand] =
for {
line <- getStrLn.orDie
command <- ZIO.fromEither(ShellCommand.fromString(line))
.tapError(putStrLn(_)) orElse userCommand
} yield command
def ls(wd: File, childOpt: Option[String]) = {
val target = childOpt.fold(wd)(p => new File(wd, p))
for {
children <- UIO(Option(target.list()).fold[List[String]](Nil)(_.toList))
_ <- ZIO.foreach(children.sorted) { child =>
putStrLn(childOpt.fold(child)(_ + "/" + child))
}
} yield ()
}
def cd(wd: Ref[File], path: String) =
wd.update(wdFile => new File(wdFile, path)) *>
wd.get.flatMap(file => putStrLn(file.getPath()))
def pwd(wd: File) = putStrLn(wd.getPath())
def consoleLoop(wd: Ref[File]): ZIO[Console, Nothing, Unit] =
for {
_ <- putStr("ZIO Shell> ")
command <- userCommand
wdFile <- wd.get
loop <- command match {
case Ls(path) => ls(wdFile, path) as true
case Cd(path) => cd(wd, path) as true
case Pwd => pwd(wdFile) as true
case Quit => putStrLn("Exiting...") as false
}
_ <- if (loop) consoleLoop(wd) else ZIO.unit
} yield ()
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
wdFile <- UIO(new File(".").getAbsoluteFile())
wd <- Ref.make(wdFile)
_ <- consoleLoop(wd)
} yield ()).exited
}
object App13 extends App with Helpers {
import zio.console._
sealed trait ShellCommand
object ShellCommand {
final case class Ls(path: Option[String]) extends ShellCommand
final case class Cd(path: String) extends ShellCommand
case object Pwd extends ShellCommand
case object Quit extends ShellCommand
def fromString(input: String): Either[String, ShellCommand] =
input.trim match {
case x if x.toLowerCase == "ls" => Right(Ls(None))
case x if x.toLowerCase startsWith "ls " => Right(Ls(Some(x.drop(3))))
case x if x.toLowerCase startsWith "cd " => Right(Cd(x.drop(3)))
case x if x.toLowerCase == "pwd" => Right(Pwd)
case x if x.toLowerCase == "quit" => Right(Quit)
case x if x.toLowerCase == "exit" => Right(Quit)
case _ => Left("Expected command but received: " + input)
}
}
import ShellCommand._
import java.io.File
trait Shell {
def shell: Shell.Service
}
object Shell {
trait Service {
def listChildren(file: File): UIO[List[String]]
val initialWorkingDirectory: UIO[File]
}
trait Live extends Shell {
val shell = new Service {
def listChildren(file: File): UIO[List[String]] =
UIO(Option(file.list()).fold[List[String]](Nil)(_.toList))
val initialWorkingDirectory: UIO[File] = UIO(new File(".").getAbsoluteFile())
}
}
object Live extends Live
def makeTest(initWd: File, map: Map[File, List[String]]): Service =
new Service {
def listChildren(file: File): UIO[List[String]] =
ZIO.fromOption(map.get(file)) orElse ZIO.succeed(Nil)
val initialWorkingDirectory: UIO[File] = UIO.succeed(initWd)
}
def listChildren(file: File): ZIO[Shell, Nothing, List[String]] =
ZIO.accessM[Shell](_.shell.listChildren(file))
val initialWorkingDirectory: ZIO[Shell, Nothing, File] =
ZIO.accessM[Shell](_.shell.initialWorkingDirectory)
}
lazy val userCommand: ZIO[Console, Nothing, ShellCommand] =
for {
line <- getStrLn.orDie
command <- ZIO.fromEither(ShellCommand.fromString(line))
.tapError(putStrLn(_)) orElse userCommand
} yield command
def ls(wd: File, childOpt: Option[String]) = {
val target = childOpt.fold(wd)(p => new File(wd, p))
for {
children <- Shell.listChildren(target)
_ <- ZIO.foreach(children.sorted) { child =>
putStrLn(childOpt.fold(child)(_ + "/" + child))
}
} yield ()
}
def cd(wd: Ref[File], path: String) =
wd.update(wdFile => new File(wdFile, path)) *>
wd.get.flatMap(file => putStrLn(file.getPath()))
def pwd(wd: File) = putStrLn(wd.getPath())
def consoleLoop(wd: Ref[File]): ZIO[Console with Shell, Nothing, Unit] =
putStr("ZIO Shell> ").flatMap(_ =>
userCommand.flatMap(command =>
wd.get.flatMap(wdFile =>
(command match {
case Ls(path) => ls(wdFile, path) as true
case Cd(path) => cd(wd, path) as true
case Pwd => pwd(wdFile) as true
case Quit => putStrLn("Exiting...") as false
}).flatMap(loop =>
if (loop) consoleLoop(wd) else ZIO.unit
)
)
)
)
final case class TestConsole(input: List[String], output: List[String]) {
final def putStrLn(line: String): TestConsole = putStr(line + "\n")
final def putStr(line: String): TestConsole =
copy(output = line :: output)
final def getStrLn: (String, TestConsole) =
(input.head, putStrLn(input.head).copy(input = input.drop(1)))
}
def makeTestConsole(ref: Ref[TestConsole]): Console.Service[Any] =
new Console.Service[Any] {
val getStrLn: ZIO[Any, IOException, String] = ref.modify(_.getStrLn)
def putStr(line: String): ZIO[Any, Nothing, Unit] = ref.update(_.putStr(line)).unit
def putStrLn(line: String): ZIO[Any, Nothing, Unit] = ref.update(_.putStrLn(line)).unit
}
val shell: ZIO[Shell with Console, Nothing, Unit] =
for {
wdFile <- Shell.initialWorkingDirectory
wd <- Ref.make(wdFile)
_ <- consoleLoop(wd)
} yield ()
def runScenario(wd: File, map: Map[File, List[String]], input: List[String]): UIO[List[String]] =
for {
ref <- Ref.make(TestConsole(input ++ List("quit"), Nil))
shell0 = Shell.makeTest(wd, map)
console0 = makeTestConsole(ref)
testEnv = new Shell with Console {
val console = console0
val shell = shell0
}
_ <- shell.provide(testEnv)
lines <- ref.get.map(_.output.reverse)
} yield lines
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
val wd = new File("root")
val child1 = new File(wd, "child1")
val child2 = new File(wd, "child2")
val grandchild1 = new File(child2, "grandchild1")
val map =
Map(
wd -> List("child1", "child2"),
child1 -> Nil,
child2 -> List("grandchild1"),
grandchild1 -> List())
(for {
lines <- runScenario(wd, map, List("pwd", "ls", "cd child2", "ls"))
_ <- putStrLn(lines.mkString(""))
} yield ()).exited
}
}
// object App14 extends App with Helpers {
// import zio.console._
// sealed trait ShellCommand
// object ShellCommand {
// final case class Ls(path: Option[String]) extends ShellCommand
// final case class Cd(path: String) extends ShellCommand
// case object Pwd extends ShellCommand
// case object Quit extends ShellCommand
// def fromString(input: String): Either[String, ShellCommand] =
// input.trim match {
// case x if x.toLowerCase == "ls" => Right(Ls(None))
// case x if x.toLowerCase startsWith "ls " => Right(Ls(Some(x.drop(3))))
// case x if x.toLowerCase startsWith "cd " => Right(Cd(x.drop(3)))
// case x if x.toLowerCase == "pwd" => Right(Pwd)
// case x if x.toLowerCase == "quit" => Right(Quit)
// case x if x.toLowerCase == "exit" => Right(Quit)
// case _ => Left("Expected command but received: " + input)
// }
// }
// import ShellCommand._
// import java.io.File
// trait Console[F[_]] {
// val getStrLn: F[String]
// def putStrLn(line: String): F[Unit]
// def putStr(line: String): F[Unit]
// }
// object Console {
// def apply[F[_]](implicit console: Console[F]): Console[F] = console
// }
// trait Shell[F[_]] {
// def listChildren(file: File): F[List[String]]
// val initialWorkingDirectory: F[File]
// }
// object Shell {
// def apply[F[_]](implicit shell: Shell[F]): Shell[F] = shell
// }
// trait Effect[F[_]] {
// def fmap[A, B](fa: F[A])(f: A => B): F[B]
// def bind[A, B](fa: F[A])(f: A => F[B]): F[B]
// def pure[A](a: A): F[A]
// }
// object Effect {
// def apply[F[_]](implicit effect: Effect[F]): Effect[F] = effect
// def pure[F[_]: Effect, A](a: A): F[A] = Effect[F].pure(a)
// }
// implicit class EffectSyntax[F[_], A](fa: F[A]) {
// def map[B](f: A => B)(implicit effect: Effect[F]): F[B] =
// effect.fmap(fa)(f)
// def flatMap[B](f: A => F[B])(implicit effect: Effect[F]): F[B] =
// effect.bind(fa)(f)
// }
// // trait Shell {
// // def shell: Shell.Service
// // }
// // object Shell {
// // trait Service {
// // def listChildren(file: File): UIO[List[String]]
// // val initialWorkingDirectory: UIO[File]
// // }
// // trait Live extends Shell {
// // val shell = new Service {
// // def listChildren(file: File): UIO[List[String]] =
// // UIO(Option(file.list()).fold[List[String]](Nil)(_.toList))
// // val initialWorkingDirectory: UIO[File] = UIO(new File(".").getAbsoluteFile())
// // }
// // }
// // object Live extends Live
// // def makeTest(initWd: File, map: Map[File, List[String]]): Service =
// // new Service {
// // def listChildren(file: File): UIO[List[String]] =
// // ZIO.fromOption(map.get(file)) orElse ZIO.succeed(Nil)
// // val initialWorkingDirectory: UIO[File] = UIO.succeed(initWd)
// // }
// // def listChildren(file: File): ZIO[Shell, Nothing, List[String]] =
// // ZIO.accessM[Shell](_.shell.listChildren(file))
// // val initialWorkingDirectory: ZIO[Shell, Nothing, File] =
// // ZIO.accessM[Shell](_.shell.initialWorkingDirectory)
// // }
// def userCommand[F[_]: Effect: Console]: F[ShellCommand] =
// for {
// line <- Console[F].getStrLn
// command <- ShellCommand.fromString(line) match {
// case Right(command) => Effect.pure(command)
// case Left(e) => Console[F].putStrLn(e).flatMap(_ => userCommand[F])
// }
// } yield command
// def ls[F[_]: Effect: Shell](wd: File, childOpt: Option[String]): F[Unit] = {
// val target = childOpt.fold(wd)(p => new File(wd, p))
// for {
// children <- Shell[F].listChildren(target)
// _ <- ZIO.foreach(children.sorted) { child =>
// putStrLn(childOpt.fold(child)(_ + "/" + child))
// }
// } yield ()
// }
// def cd(wd: Ref[File], path: String) =
// wd.update(wdFile => new File(wdFile, path)) *>
// wd.get.flatMap(file => putStrLn(file.getPath()))
// def pwd(wd: File) = putStrLn(wd.getPath())
// def consoleLoop(wd: Ref[File]): ZIO[Console with Shell, Nothing, Unit] =
// putStr("ZIO Shell> ").flatMap(_ =>
// userCommand.flatMap(command =>
// wd.get.flatMap(wdFile =>
// (command match {
// case Ls(path) => ls(wdFile, path) as true
// case Cd(path) => cd(wd, path) as true
// case Pwd => pwd(wdFile) as true
// case Quit => putStrLn("Exiting...") as false
// }).flatMap(loop =>
// if (loop) consoleLoop(wd) else ZIO.unit
// )
// )
// )
// )
// final case class TestConsole(input: List[String], output: List[String]) {
// final def putStrLn(line: String): TestConsole = putStr(line + "\n")
// final def putStr(line: String): TestConsole =
// copy(output = line :: output)
// final def getStrLn: (String, TestConsole) =
// (input.head, putStrLn(input.head).copy(input = input.drop(1)))
// }
// def makeTestConsole(ref: Ref[TestConsole]): Console.Service[Any] =
// new Console.Service[Any] {
// val getStrLn: ZIO[Any, IOException, String] = ref.modify(_.getStrLn)
// def putStr(line: String): ZIO[Any, Nothing, Unit] = ref.update(_.putStr(line)).unit
// def putStrLn(line: String): ZIO[Any, Nothing, Unit] = ref.update(_.putStrLn(line)).unit
// }
// val shell: ZIO[Shell with Console, Nothing, Unit] =
// for {
// wdFile <- Shell.initialWorkingDirectory
// wd <- Ref.make(wdFile)
// _ <- consoleLoop(wd)
// } yield ()
// def runScenario(wd: File, map: Map[File, List[String]], input: List[String]): UIO[List[String]] =
// for {
// ref <- Ref.make(TestConsole(input ++ List("quit"), Nil))
// shell0 = Shell.makeTest(wd, map)
// console0 = makeTestConsole(ref)
// testEnv = new Shell with Console {
// val console = console0
// val shell = shell0
// }
// _ <- shell.provide(testEnv)
// lines <- ref.get.map(_.output.reverse)
// } yield lines
// def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
// val wd = new File("root")
// val child1 = new File(wd, "child1")
// val child2 = new File(wd, "child2")
// val grandchild1 = new File(child2, "grandchild1")
// val map =
// Map(
// wd -> List("child1", "child2"),
// child1 -> Nil,
// child2 -> List("grandchild1"),
// grandchild1 -> List())
// (for {
// lines <- runScenario(wd, map, List("pwd", "ls", "cd child2", "ls"))
// _ <- putStrLn(lines.mkString(""))
// } yield ()).exited
// }
// }
object App15 extends App with Helpers {
import zio.stm._
import scala.collection.immutable.{ Queue => ScalaQueue }
final case class ConcurrentQueue[A] private (capacity: Int, ref: TRef[ScalaQueue[A]]) {
final def take: UIO[A] =
(for {
queue <- ref.get
a <- queue.headOption.fold[STM[Nothing, A]](STM.retry)(a => STM.succeed(a))
_ <- ref.update(_.drop(1))
} yield a).commit
final def offer(a: A): UIO[Unit] =
(for {
queue <- ref.get
_ <- STM.check(queue.size < capacity)
_ <- ref.set(queue.enqueue(a))
} yield ()).commit
}
object ConcurrentQueue {
def make[A](capacity: Int): UIO[ConcurrentQueue[A]] =
for {
ref <- TRef.make(ScalaQueue.empty[A]).commit
} yield new ConcurrentQueue(capacity, ref)
}
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
queue <- ConcurrentQueue.make[Int](10)
_ <- queue.take.flatMap(i => console.putStrLn(i.toString)).forever.fork
_ <- queue.offer(1) *> queue.offer(2) *> queue.offer(3)
} yield ()).exited
}
object App16 extends App with Helpers {
import zio.console._
import zio.random._
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
_ <- putStrLn("Beginning App16 example")
v <- nextInt(100)
_ <- putStrLn(s"Random number is ${v}")
_ <- ZIO.fail("Uh oh!")
} yield ()).catchAllCause(cause => putStrLn(cause.prettyPrint)).exited
}
object App17 extends App with Helpers {
import scala.concurrent._
import zio.console._
import zio.blocking.blocking
def myLegacyCode(s: String)(implicit ec: ExecutionContext): Future[Unit] =
Future.successful(s).map(_ => ())
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
blocking {
ZIO.fromFuture { implicit ec => myLegacyCode("foo") }
}.exited
unsafeRunToFuture(putStrLn("hello world").provide(Console.Live))
}
object App18 extends App with Helpers {
import zio.console._
import zio.random._
import zio.duration._
/**
* Produce a jittered schedule that first does exponential spacing (starting
* from 10 milliseconds), but then after the spacing reaches 60 seconds,
* switches over to fixed spacing of 60 seconds between recurrences, but will
* only do that for up to 100 times, and produce a list of the inputs to
* the schedule.
*/
def exampleSchedule[A]: ZSchedule[Random, A, List[A]] =
(Schedule.exponential(10.millis).whileOutput(_ <= 60.seconds) andThen
(Schedule.spaced(60.seconds) && Schedule.recurs(100)).jittered) *>
Schedule.identity.collectAll
val flakyEffect: ZIO[Console with Random, String, Unit] =
random.nextBoolean.flatMap {
case true => putStrLn("Hello")
case false => ZIO.fail("Uh oh!")
}
val reliableEffect = putStrLn("Executed")
val moreReliableFlakyEffect = flakyEffect retry exampleSchedule[String]
val repeatedReliableEffect = reliableEffect repeat exampleSchedule[Unit]
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
ZIO.unit.exited
}
object App19 extends App with Helpers {
trait Request
trait Response
type Handler = Request => UIO[Response]
type CreateHandler = UIO[Handler]
val requestHandler: Handler = ???
def server(createHandler: CreateHandler): UIO[Unit] = ???
def rateLimited(n: Int)(handler: Handler): UIO[CreateHandler] =
for {
semaphore <- Semaphore.make(n)
} yield semaphore.withPermit(UIO(r => handler(r)))
def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
(for {
createHandler <- rateLimited(100)(requestHandler)
_ <- server(createHandler)
} yield ()).exited
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment