Last active
May 24, 2021 19:31
Star
You must be signed in to star a gist
ZIO Workshop - Sky
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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