Skip to content

Instantly share code, notes, and snippets.

@gustavofranke
Created June 30, 2020 11:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gustavofranke/e97f053c613cc719ff5653b8201a5534 to your computer and use it in GitHub Desktop.
Save gustavofranke/e97f053c613cc719ff5653b8201a5534 to your computer and use it in GitHub Desktop.
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