Created
June 30, 2020 11:01
-
-
Save gustavofranke/e97f053c613cc719ff5653b8201a5534 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 playground | |
// https://www.youtube.com/watch?v=xpz4rf1RS8c | |
// 01. functional effects | |
// Console - Model 1 | |
sealed trait Console1 { self => | |
def +(that: Console1): Console1 = Sequence1(self, that) | |
} | |
final case class Print1(line: String) extends Console1 | |
final case class Sequence1(first: Console1, second: Console1) extends Console1 | |
object ProgramConsole1 extends App { | |
val program = | |
Print1("Hello") + | |
Print1("\n") + | |
Print1("World!") | |
final def run(console: Console1): Unit = console match { | |
case Print1(line) => println(line) | |
case Sequence1(first, second) => run(first) ; run(second) | |
} | |
run(program) | |
} | |
// Console - Model 2 | |
sealed trait Console[+A] | |
final case class Return[A](value: A) extends Console[A] | |
final case class Print[A](line: String, k: Console[A]) extends Console[A] | |
final case class Read[A](k: String => Console[A]) extends Console[A] | |
object ProgramConsole2 extends App { | |
lazy val program: Console[String] = | |
Print("What is your name?", | |
Read(name => | |
Print(s"Hello, $name!", Return(name))) | |
) | |
@scala.annotation.tailrec | |
final def run[A](console: Console[A]): A = | |
console match { | |
case Return(value) => value | |
case Print(line, k) => println(line) ; run(k) | |
case Read(k) => run(k(scala.io.StdIn.readLine())) | |
} | |
val a: String = run(program) | |
println(s"in println: $a") | |
} | |
// 02. unveiling zio | |
final case class ZIO[-R, +E, +A](run: R => Either[E, A]) { self => | |
def map[B](f: A=> B): ZIO[R, E, B] = | |
ZIO(r => run(r).map(f)) | |
def flatMap[R1 <: R, E1 >: E, B](f: A => ZIO[R1, E1, B]): ZIO[R1, E1, B] = | |
ZIO(r => run(r).flatMap(a => f(a).run(r))) | |
def provide(r: R): ZIO[Any, E, A] = | |
ZIO(_ => run(r)) | |
def either: ZIO[R, Nothing, Either[E, A]] = | |
ZIO(r => Right(run(r))) | |
def zip[R1 <: R, E1 >: E, B](that: => ZIO[R1, E1, B]): ZIO[R1, E1, (A, B)] = | |
self flatMap (a => that map (b => (a, b))) | |
def <* [R1 <: R, E1 >: E, B](that: => ZIO[R1, E1, B]): ZIO[R1, E1, A] = | |
(self zip that) map (_._1) | |
def *> [R1 <: R, E1 >: E, B](that: => ZIO[R1, E1, B]): ZIO[R1, E1, B] = | |
(self zip that) map (_._2) | |
def forever[R, E](zio: ZIO[R, E, Any]): ZIO[R, E, Nothing] = | |
zio *> forever(zio) | |
def eventually[R, A](zio: ZIO[R, Any, A]): ZIO[R, Nothing, A] = | |
zio orElse eventually(zio) | |
// zio.flip.forever.flip | |
// def orElse[R, A](value: ZIO[R, Nothing, A]) = ??? | |
def orElse[R1 <: R, E2, A1 >: A](that: => ZIO[R1, E2, A1]): ZIO[R1, E2, A1] = ??? | |
def flip[R, E, A]: ZIO[R, A, E] = ??? | |
def mapError[R, E, E1, A](zio: ZIO[R, E, A])(f: E => E1): ZIO[R, E1, A] = | |
zio.flip.map(f).flip | |
} | |
object ZIO { | |
def succeed[A](a: A): ZIO[Any, Nothing, A] = | |
ZIO(_ => Right(a)) | |
def environment[R]: ZIO[R, Nothing, R] = | |
ZIO(r => Right(r)) | |
def effect[A](action: => A): ZIO[Any, Throwable, A] = | |
ZIO { _ => | |
try Right(action) | |
catch { | |
case t: Throwable => Left(t) | |
} | |
} | |
def die(t: Throwable): ZIO[Any, Nothing, Nothing] = | |
ZIO(_ => throw t) | |
} | |
object ZIOExampleProgram { | |
def putStrLn(line: String): ZIO[Any, Throwable, Unit] = ZIO.effect(println(line)) | |
val getStrLn: ZIO[Any, Throwable, String] = ZIO.effect(scala.io.StdIn.readLine()) | |
val program: ZIO[Any, Throwable, String] = | |
for { | |
_ <- putStrLn("Hello, what is your name?") | |
name <- getStrLn | |
_ <- putStrLn(s"Good to meet you, $name") | |
} yield name | |
} | |
// 03 magic tricks | |
object FallbackZIO { | |
type IO[+E, +A] = ZIO[Any, E, A] // Succeed with an `A`, may fail with `E` , no requirements. | |
type Task[+A] = ZIO[Any, Throwable, A] // Succeed with an `A`, may fail with `Throwable`, no requirements. | |
type RIO[-R, +A] = ZIO[R, Throwable, A] // Succeed with an `A`, may fail with `Throwable`, requires an `R`. | |
type UIO[+A] = ZIO[Any, Nothing, A] // Succeed with an `A`, cannot fail , no requirements. | |
type URIO[-R, +A] = ZIO[R, Nothing, A] // Succeed with an `A`, cannot fail , requires an `R`. | |
// 27:32 | |
case class Data() | |
def getFromCache(v: String): Task[Data] = ZIO.succeed(Data()) | |
def getFromDatabase(v: String): Task[Data] = ZIO.succeed(Data()) | |
def getFromConfig(v: String): UIO[Data] = ZIO.succeed(Data()) | |
def getFromSomewhere(v: String): UIO[Data] = | |
getFromCache(v) | |
.orElse(getFromDatabase(v)) | |
.orElse(getFromConfig(v)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment