Queue
Wiem Zine Elabidine
Milan Scala Group
Intro
Tour of ZIO
Intro
Tour of ZIO
Queue
Intro
Wrap up
Tour of ZIO
Queue
Intro
First point
John De Goes revealed the high performance of Scalaz8 Effect.
Motivation
The Scalaz8 effect is moved to a new
library Scalaz-zio with zero dependencies.
Good news!
What is ZIO?
ZIO provides purely functional data
structures with an abstraction for the
effectful programs using monads.
Effectful program
● Interaction with the real World
● Hard to reason about
● Hard to test
● Refactoring
● Programming without effects is useless
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
parseInt("Hello!")
[error] java.lang.NumberFormatException:
For input string: "Hello!"
NOT TOTAL!
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
addOne(10)
> 4
addOne(10)
> 6
addOne(10)
> 2
NON DETERMINISTIC!
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
SIDE EFFECT!
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
SIDE EFFECT!
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
def program(): = { }
Properties of pure functions
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
Pure functions
def parseInt(s: String): Option[Int] =
Try(s.toInt).toOption
def addOne(x: Int): Int = x + 1
def buyCoffee(cc: CreditCard): (Coffee, Charge) = {
val cup = new Coffee()
(cup, Charge(cc, cup.price))
}
def program(): = { }
Properties of pure functions
Pure functions
def parseInt(s: String): Option[Int] =
Try(s.toInt).toOption
def addOne(x: Int): Int = x + 1
def buyCoffee(cc: CreditCard): (Coffee, Charge) =
{
val cup = new Coffee()
(cup, Charge(cc, cup.price))
}
Non-pure functions
def parseInt(s: String): Int = s.toInt
def addOne(x: Int): Int = Random.nextInt(x) + 1
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
def program(): = { } def program(): = { }
Properties of pure functions
● Total
● Deterministic
● Free of side effects
TOUR OF
What is IO[E, A] ?
IO is an immutable data structure that describes an
effectful program that may:
● fail with an E
● run forever
● produce a single A
What is IO[E, A] ?
parseInt("hello") //fails with NumberFormatExceptionIO.syncException(parseInt(str))
What is IO?
parseInt("1")IO.syncException(parseInt(str))
What is IO[E, A] ?
println("Hello!")IO.sync(println("Hello!")
What is IO[E, A] ?
throw new Exception("error")IO.fail(new Exception("error"))
What is IO[E, A] ?
while(true) {}IO.never
IO[E, A] structure
trait IO[E, A] { self =>
def map[B](f: A => B): IO[E, B]
def flatMap[E, B](f0: A => IO[E, B]): IO[E, B]
...
}
object IO {
def fail[E](error: E): IO[E, Nothing] = ???
def now[A](a: A): IO[Nothing, A] = ???
...
}
IO[E, A]
IO Effects
IO describes the following effects:
● Pure Values
val number: Int= 1
val number: IO[Nothing, Int] = IO.now(1)
IO Effects
IO describes the following effects:
● Pure Values
● Synchronous Effect
println("hello")
val putStrLn: IO[Nothing, Unit] =
IO.sync(println("hello"))
IO Effects
IO describes the following effects:
● Pure Values
● Synchronous Effect
parseInt("hello")
val toInt: IO[Throwable, Int] =
IO.syncThrowable(parseInt("hello"))
IO Effects
IO describes the following effects:
● Pure Values
● Synchronous Effect
parseInt("hello")
val toInt: IO[Exception, Int] =
IO.syncException(parseInt("hello"))
IO Effects
IO describes the following effects:
● Pure Values
● Synchronous Effect
parseInt("hello")
val toInt: IO[String, Int] =
IO.syncCatch(parseInt("hello")){
case e: NumberFormatException => "oh no!"
}
IO Effects
IO describes the following effects:
● Pure Values
● Synchronous Effect
● Asynchronous Effects
Future(4)
IO.async[Nothing, Int](_(Completed(4)))
IO Effects
IO describes the following effects:
● Pure Values
● Synchronous Effect
● Asynchronous Effects
● Concurrent Effects
val hello = new Thread(new Runnable {
def run() {
while (true) {
println("hello world")
}
}
})
for {
f <- IO.sync(println("hello world")).fork
_ <- f.join
} yield ()
IO Effects
IO describes the following effects:
● Pure Values
● Synchronous Effect
● Asynchronous Effects
● Concurrent Effects
val hello = new Thread(new Runnable {
def run() {
while (true) {
println("hello world")
}
}
})
for {
f <- IO.sync(println("hello world")).forever.fork
_ <- f.interrupt
} yield ()
IO Effects
IO describes the following effects:
● Pure Values
● Synchronous Effect
● Asynchronous Effects
● Concurrent Effects
● Resource Effects
val f: File = openFile()
try {
compute(f)
}
finally {
closeFile(f) //Unit
}
IO.bracket[Error, File, Unit](openFile())
(f => closeFile(f))(f => compute(f))
Usage of IO
In ZIO, every type has specific
features to solve different problems.
Each type is wrapped inside an IO.
Promise[E, A]
Ref[A]
Queue[A]
IO[E, A]
RTS: IO runtime system
IO is interpreted by the IO runtime system into
effectful interactions with the external world.
● unsafeRun
● In your application’s main function (App
provides this functionality automatically).
def main(args: Array[String]): Unit =
println("Hello")
def main(args: Array[String]): Unit =
unsafeRun(IO.sync(println("Hello")))
Ref
Ref is the equivalent of `var`
Ref has an AtomicReference to apply the
atomic operations on it.
Ref
Ref[A]
object Ref {
def apply[A](a: A): IO[Nothing, Ref[A]] = ???
}
trait Ref[A] {
def get: IO[Nothing, A]
def set(a: A): IO[Nothing, Unit]
def update(f: A => A): IO[Nothing, A]
def modify[B](f: A => (B, A)): IO[Nothing, B]
}
Example
for {
counter <- Ref(0)
v <- counter.update(_ + 1)
} yield v
for {
counter <- Ref(0)
v <- counter.modify {
prev =>
val newValue = prev + 1
(s"previous value: $prev, next value is: $newValue", newValue)
}
_ <- IO.sync(println(v))
} yield ()
Promise
A Promise is an asynchronous variable that
can be set only once.
Promise
A Promise is an asynchronous variable that
can be set only once.
`error`: fails the promise with the specified error, which will be
propagated to all fibers waiting on the value of promise.
Promise
A Promise is an asynchronous variable that
can be set only once.
`complete`: completes the promise with the specified value.
Promise
By default the state of Promise is Pending, once it fails or completes
the state changes to Done.
`done`: completes the promise with the specified result.
A Promise is an asynchronous variable that
can be set only once.
Promise
trait Promise[E, A] {
def get: IO[E, A]
def complete(a: A): IO[Nothing, Boolean]
def error(e: E): IO[Nothing, Boolean]
def interrupt(t: Throwable): IO[Nothing, Boolean]
def done(r: ExitResult[E, A]): IO[Nothing, Boolean]
}
Promise[E, A]
object Promise {
def make[E, A]: IO[Nothing, Promise[E, A]] = ???
}
Promise: Example
Get an alert for your friends’s
birthday, as follow up reminder to
offer the appropriate “happy
birthday” greeting.
🎂
Promise: Example
(for {
p <- Promise.make[Nothing, String]
_ <- p.complete(s"Your reminder for ${friend.name} birthday")
.delay(minus(LocalDate.now, friend.birthday))
.fork
msg <- p.get
} yield sendAlert(msg)).fork
20.12.2018
QUEUE
Queue
Queue is an asynchronous queue which allows to
add and remove elements in First In First Out
manner.
...
V6
V5
V4
V3
V2
V1
offer* take*
Queue
Producers Consumers
trait Queue[A] {
def take: IO[Nothing, A]
def takeAll: IO[Nothing, List[A]]
def takeUpTo(max: Int): IO[Nothing, List[A]]
def offer(a: A): IO[Nothing, Boolean]
def offerAll(as: Iterable[A]): IO[Nothing, Boolean]
}
object Queue {
def bounded[A](capacity: Int): IO[Nothing, Queue[A]]
def unbounded[A]: IO[Nothing, Queue[A]]
def sliding[A](capacity: Int): IO[Nothing, Queue[A]]
def dropping[A](capacity: Int): IO[Nothing, Queue[A]]
}
Queue[A]
Queue
Takers
take
Consumers
for {
queue <- Queue.unbounded[String]
v1 <- queue.take.fork
Takers
take
take
Consumers
for {
queue <- Queue.unbounded[String]
v1 <- queue.take.fork
v2 <- queue.take.fork
Takers
take
take
Consumers
for {
queue <- Queue.unbounded[String]
v1 <- queue.take.fork
v2 <- queue.take.fork
_ <- queue.offer("hello").fork
“hello”
Producers
Takers
take
take
Consumers
for {
queue <- Queue.unbounded[String]
v1 <- queue.take.fork
v2 <- queue.take.fork
_ <- queue.offer("hello").fork
_ <- queue.offer("bye").fork
Producers
“hello”
“bye”
Takers
take
take
Consumers
for {
queue <- Queue.unbounded[String]
v1 <- queue.take.fork
v2 <- queue.take.fork
_ <- queue.offer("hello").fork
_ <- queue.offer("bye").fork
Producers
“bye”
“hello”
Takers
Consumers
for {
queue <- Queue.unbounded[String]
v1 <- queue.take.fork
v2 <- queue.take.fork
_ <- queue.offer("hello").fork
_ <- queue.offer("bye").fork
} yield ()
Producers
“hello”
“bye”
Back pressure
A bounded Queue with capacity = 3
for {
queue <- Queue.bounded[String](3)
Back pressure
“b”
“c”
“a”
“d”
“b”
“c”
Producers
for {
queue <- Queue.bounded[String](3)
_ <- queue.offer("a").fork
_ <- queue.offer("b").fork
_ <- queue.offer("c").fork
_ <- queue.offer("d").fork
Back pressure
“c”
“b”
“a”
offer(“d”)
Producers
for {
queue <- Queue.bounded[String](3)
_ <- queue.offer("a").fork
_ <- queue.offer("b").fork
_ <- queue.offer("c").fork
_ <- queue.offer("d").fork
Back pressure
take
offer(“d”)
ConsumersProducers
for {
queue <- Queue.bounded[String](3)
_ <- queue.offer("a").fork
_ <- queue.offer("b").fork
_ <- queue.offer("c").fork
_ <- queue.offer("d").fork
v1 <- queue.take.fork
“c”
“b”
“a”
Back pressure
“c”
“b”
offer(“d”)
Consumers
“a”
Producers
for {
queue <- Queue.bounded[String](3)
_ <- queue.offer("a").fork
_ <- queue.offer("b").fork
_ <- queue.offer("c").fork
_ <- queue.offer("d").fork
v1 <- queue.take.fork
Back pressure
“d”
“c”
“b”
ConsumersProducers
for {
queue <- Queue.bounded[String](3)
_ <- queue.offer("a").fork
_ <- queue.offer("b").fork
_ <- queue.offer("c").fork
_ <- queue.offer("d").fork
v1 <- queue.take.fork
} yield ()
Sliding
for {
queue <- Queue.sliding[String](3)
_ <- queue.offer("A") //(1)
} yield ()
Sliding
for {
queue <- Queue.sliding[String](3)
_ <- queue.offer("A") //(1)
_ <- queue.offer("B") //(2)
} yield ()
Sliding
for {
queue <- Queue.sliding[String](3)
_ <- queue.offer("A") //(1)
_ <- queue.offer("B") //(2)
_ <- queue.offer("C") //(3)
} yield ()
Sliding
for {
queue <- Queue.sliding[String](3)
_ <- queue.offer("A") //(1)
_ <- queue.offer("B") //(2)
_ <- queue.offer("C") //(3)
_ <- queue.offer("D") //(4)
} yield ()
Sliding
for {
queue <- Queue.sliding[String](3)
_ <- queue.offer("A") //(1)
_ <- queue.offer("B") //(2)
_ <- queue.offer("C") //(3)
_ <- queue.offer("D") //(4)
} yield ()
Dropping
for {
queue <- Queue.dropping[String](3)
_ <- queue.offer("A") //(1)
} yield ()
Dropping
for {
queue <- Queue.dropping[String](3)
_ <- queue.offer("A") //(1)
_ <- queue.offer("B") //(2)
} yield ()
Dropping
for {
queue <- Queue.dropping[String](3)
_ <- queue.offer("A") //(1)
_ <- queue.offer("B") //(2)
_ <- queue.offer("C") //(3)
} yield ()
Dropping
for {
queue <- Queue.dropping[String](3)
_ <- queue.offer("A") //(1)
_ <- queue.offer("B") //(2)
_ <- queue.offer("C") //(3)
_ <- queue.offer("D") //(4)
} yield ()
Dropping
for {
queue <- Queue.dropping[String](3)
_ <- queue.offer("A") //(1)
_ <- queue.offer("B") //(2)
_ <- queue.offer("D") //(4)
} yield ()
Shutdown
for {
queue <- Queue.unbounded[String]
_ <- queue.offer("A").forever.fork
_ <- queue.take.forever.fork
} yield ()
Shutdown
for {
queue <- Queue.unbounded[String]
_ <- queue.offer("A").forever.fork
_ <- queue.take.forever.fork
_ <- queue.shutdown
} yield ()
Shutdown
for {
queue <- Queue.unbounded[String]
_ <- queue.offer("A").forever.fork
_ <- queue.take.forever.fork
_ <- queue.shutdown
} yield ()
Wrap up
Wrap Up
github.com/scalaz/scalaz-zio
Wrap Up
https://gitter.im/scalaz/scalaz-zio/
https://javadoc.io/doc/org.scalaz/scalaz-zio_2.12/0.5.1
https://scalaz.github.io/scalaz-zio/
Thank you
@WiemZin
wi101

ZIO Queue

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
    Wrap up Tour ofZIO Queue Intro
  • 6.
    First point John DeGoes revealed the high performance of Scalaz8 Effect.
  • 7.
  • 8.
    The Scalaz8 effectis moved to a new library Scalaz-zio with zero dependencies. Good news!
  • 9.
    What is ZIO? ZIOprovides purely functional data structures with an abstraction for the effectful programs using monads.
  • 10.
    Effectful program ● Interactionwith the real World ● Hard to reason about ● Hard to test ● Refactoring ● Programming without effects is useless
  • 11.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup }
  • 12.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup } parseInt("Hello!") [error] java.lang.NumberFormatException: For input string: "Hello!" NOT TOTAL!
  • 13.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup }
  • 14.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup } addOne(10) > 4 addOne(10) > 6 addOne(10) > 2 NON DETERMINISTIC!
  • 15.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup }
  • 16.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup } SIDE EFFECT!
  • 17.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup } SIDE EFFECT!
  • 18.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup } def program(): = { }
  • 19.
    Properties of purefunctions Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup } Pure functions def parseInt(s: String): Option[Int] = Try(s.toInt).toOption def addOne(x: Int): Int = x + 1 def buyCoffee(cc: CreditCard): (Coffee, Charge) = { val cup = new Coffee() (cup, Charge(cc, cup.price)) } def program(): = { }
  • 20.
    Properties of purefunctions Pure functions def parseInt(s: String): Option[Int] = Try(s.toInt).toOption def addOne(x: Int): Int = x + 1 def buyCoffee(cc: CreditCard): (Coffee, Charge) = { val cup = new Coffee() (cup, Charge(cc, cup.price)) } Non-pure functions def parseInt(s: String): Int = s.toInt def addOne(x: Int): Int = Random.nextInt(x) + 1 def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() p.charge(cc, cup.price) cup } def program(): = { } def program(): = { }
  • 21.
    Properties of purefunctions ● Total ● Deterministic ● Free of side effects
  • 22.
  • 23.
    What is IO[E,A] ? IO is an immutable data structure that describes an effectful program that may: ● fail with an E ● run forever ● produce a single A
  • 24.
    What is IO[E,A] ? parseInt("hello") //fails with NumberFormatExceptionIO.syncException(parseInt(str))
  • 25.
  • 26.
    What is IO[E,A] ? println("Hello!")IO.sync(println("Hello!")
  • 27.
    What is IO[E,A] ? throw new Exception("error")IO.fail(new Exception("error"))
  • 28.
    What is IO[E,A] ? while(true) {}IO.never
  • 29.
    IO[E, A] structure traitIO[E, A] { self => def map[B](f: A => B): IO[E, B] def flatMap[E, B](f0: A => IO[E, B]): IO[E, B] ... } object IO { def fail[E](error: E): IO[E, Nothing] = ??? def now[A](a: A): IO[Nothing, A] = ??? ... } IO[E, A]
  • 30.
    IO Effects IO describesthe following effects: ● Pure Values val number: Int= 1 val number: IO[Nothing, Int] = IO.now(1)
  • 31.
    IO Effects IO describesthe following effects: ● Pure Values ● Synchronous Effect println("hello") val putStrLn: IO[Nothing, Unit] = IO.sync(println("hello"))
  • 32.
    IO Effects IO describesthe following effects: ● Pure Values ● Synchronous Effect parseInt("hello") val toInt: IO[Throwable, Int] = IO.syncThrowable(parseInt("hello"))
  • 33.
    IO Effects IO describesthe following effects: ● Pure Values ● Synchronous Effect parseInt("hello") val toInt: IO[Exception, Int] = IO.syncException(parseInt("hello"))
  • 34.
    IO Effects IO describesthe following effects: ● Pure Values ● Synchronous Effect parseInt("hello") val toInt: IO[String, Int] = IO.syncCatch(parseInt("hello")){ case e: NumberFormatException => "oh no!" }
  • 35.
    IO Effects IO describesthe following effects: ● Pure Values ● Synchronous Effect ● Asynchronous Effects Future(4) IO.async[Nothing, Int](_(Completed(4)))
  • 36.
    IO Effects IO describesthe following effects: ● Pure Values ● Synchronous Effect ● Asynchronous Effects ● Concurrent Effects val hello = new Thread(new Runnable { def run() { while (true) { println("hello world") } } }) for { f <- IO.sync(println("hello world")).fork _ <- f.join } yield ()
  • 37.
    IO Effects IO describesthe following effects: ● Pure Values ● Synchronous Effect ● Asynchronous Effects ● Concurrent Effects val hello = new Thread(new Runnable { def run() { while (true) { println("hello world") } } }) for { f <- IO.sync(println("hello world")).forever.fork _ <- f.interrupt } yield ()
  • 38.
    IO Effects IO describesthe following effects: ● Pure Values ● Synchronous Effect ● Asynchronous Effects ● Concurrent Effects ● Resource Effects val f: File = openFile() try { compute(f) } finally { closeFile(f) //Unit } IO.bracket[Error, File, Unit](openFile()) (f => closeFile(f))(f => compute(f))
  • 39.
    Usage of IO InZIO, every type has specific features to solve different problems. Each type is wrapped inside an IO. Promise[E, A] Ref[A] Queue[A] IO[E, A]
  • 40.
    RTS: IO runtimesystem IO is interpreted by the IO runtime system into effectful interactions with the external world. ● unsafeRun ● In your application’s main function (App provides this functionality automatically). def main(args: Array[String]): Unit = println("Hello") def main(args: Array[String]): Unit = unsafeRun(IO.sync(println("Hello")))
  • 41.
    Ref Ref is theequivalent of `var` Ref has an AtomicReference to apply the atomic operations on it.
  • 42.
    Ref Ref[A] object Ref { defapply[A](a: A): IO[Nothing, Ref[A]] = ??? } trait Ref[A] { def get: IO[Nothing, A] def set(a: A): IO[Nothing, Unit] def update(f: A => A): IO[Nothing, A] def modify[B](f: A => (B, A)): IO[Nothing, B] }
  • 43.
    Example for { counter <-Ref(0) v <- counter.update(_ + 1) } yield v for { counter <- Ref(0) v <- counter.modify { prev => val newValue = prev + 1 (s"previous value: $prev, next value is: $newValue", newValue) } _ <- IO.sync(println(v)) } yield ()
  • 44.
    Promise A Promise isan asynchronous variable that can be set only once.
  • 45.
    Promise A Promise isan asynchronous variable that can be set only once. `error`: fails the promise with the specified error, which will be propagated to all fibers waiting on the value of promise.
  • 46.
    Promise A Promise isan asynchronous variable that can be set only once. `complete`: completes the promise with the specified value.
  • 47.
    Promise By default thestate of Promise is Pending, once it fails or completes the state changes to Done. `done`: completes the promise with the specified result. A Promise is an asynchronous variable that can be set only once.
  • 48.
    Promise trait Promise[E, A]{ def get: IO[E, A] def complete(a: A): IO[Nothing, Boolean] def error(e: E): IO[Nothing, Boolean] def interrupt(t: Throwable): IO[Nothing, Boolean] def done(r: ExitResult[E, A]): IO[Nothing, Boolean] } Promise[E, A] object Promise { def make[E, A]: IO[Nothing, Promise[E, A]] = ??? }
  • 49.
    Promise: Example Get analert for your friends’s birthday, as follow up reminder to offer the appropriate “happy birthday” greeting. 🎂
  • 50.
    Promise: Example (for { p<- Promise.make[Nothing, String] _ <- p.complete(s"Your reminder for ${friend.name} birthday") .delay(minus(LocalDate.now, friend.birthday)) .fork msg <- p.get } yield sendAlert(msg)).fork 20.12.2018
  • 51.
  • 52.
    Queue Queue is anasynchronous queue which allows to add and remove elements in First In First Out manner.
  • 53.
  • 54.
    trait Queue[A] { deftake: IO[Nothing, A] def takeAll: IO[Nothing, List[A]] def takeUpTo(max: Int): IO[Nothing, List[A]] def offer(a: A): IO[Nothing, Boolean] def offerAll(as: Iterable[A]): IO[Nothing, Boolean] } object Queue { def bounded[A](capacity: Int): IO[Nothing, Queue[A]] def unbounded[A]: IO[Nothing, Queue[A]] def sliding[A](capacity: Int): IO[Nothing, Queue[A]] def dropping[A](capacity: Int): IO[Nothing, Queue[A]] } Queue[A] Queue
  • 55.
    Takers take Consumers for { queue <-Queue.unbounded[String] v1 <- queue.take.fork
  • 56.
    Takers take take Consumers for { queue <-Queue.unbounded[String] v1 <- queue.take.fork v2 <- queue.take.fork
  • 57.
    Takers take take Consumers for { queue <-Queue.unbounded[String] v1 <- queue.take.fork v2 <- queue.take.fork _ <- queue.offer("hello").fork “hello” Producers
  • 58.
    Takers take take Consumers for { queue <-Queue.unbounded[String] v1 <- queue.take.fork v2 <- queue.take.fork _ <- queue.offer("hello").fork _ <- queue.offer("bye").fork Producers “hello” “bye”
  • 59.
    Takers take take Consumers for { queue <-Queue.unbounded[String] v1 <- queue.take.fork v2 <- queue.take.fork _ <- queue.offer("hello").fork _ <- queue.offer("bye").fork Producers “bye” “hello”
  • 60.
    Takers Consumers for { queue <-Queue.unbounded[String] v1 <- queue.take.fork v2 <- queue.take.fork _ <- queue.offer("hello").fork _ <- queue.offer("bye").fork } yield () Producers “hello” “bye”
  • 61.
    Back pressure A boundedQueue with capacity = 3 for { queue <- Queue.bounded[String](3)
  • 62.
    Back pressure “b” “c” “a” “d” “b” “c” Producers for { queue<- Queue.bounded[String](3) _ <- queue.offer("a").fork _ <- queue.offer("b").fork _ <- queue.offer("c").fork _ <- queue.offer("d").fork
  • 63.
    Back pressure “c” “b” “a” offer(“d”) Producers for { queue<- Queue.bounded[String](3) _ <- queue.offer("a").fork _ <- queue.offer("b").fork _ <- queue.offer("c").fork _ <- queue.offer("d").fork
  • 64.
    Back pressure take offer(“d”) ConsumersProducers for { queue<- Queue.bounded[String](3) _ <- queue.offer("a").fork _ <- queue.offer("b").fork _ <- queue.offer("c").fork _ <- queue.offer("d").fork v1 <- queue.take.fork “c” “b” “a”
  • 65.
    Back pressure “c” “b” offer(“d”) Consumers “a” Producers for { queue<- Queue.bounded[String](3) _ <- queue.offer("a").fork _ <- queue.offer("b").fork _ <- queue.offer("c").fork _ <- queue.offer("d").fork v1 <- queue.take.fork
  • 66.
    Back pressure “d” “c” “b” ConsumersProducers for { queue<- Queue.bounded[String](3) _ <- queue.offer("a").fork _ <- queue.offer("b").fork _ <- queue.offer("c").fork _ <- queue.offer("d").fork v1 <- queue.take.fork } yield ()
  • 67.
    Sliding for { queue <-Queue.sliding[String](3) _ <- queue.offer("A") //(1) } yield ()
  • 68.
    Sliding for { queue <-Queue.sliding[String](3) _ <- queue.offer("A") //(1) _ <- queue.offer("B") //(2) } yield ()
  • 69.
    Sliding for { queue <-Queue.sliding[String](3) _ <- queue.offer("A") //(1) _ <- queue.offer("B") //(2) _ <- queue.offer("C") //(3) } yield ()
  • 70.
    Sliding for { queue <-Queue.sliding[String](3) _ <- queue.offer("A") //(1) _ <- queue.offer("B") //(2) _ <- queue.offer("C") //(3) _ <- queue.offer("D") //(4) } yield ()
  • 71.
    Sliding for { queue <-Queue.sliding[String](3) _ <- queue.offer("A") //(1) _ <- queue.offer("B") //(2) _ <- queue.offer("C") //(3) _ <- queue.offer("D") //(4) } yield ()
  • 72.
    Dropping for { queue <-Queue.dropping[String](3) _ <- queue.offer("A") //(1) } yield ()
  • 73.
    Dropping for { queue <-Queue.dropping[String](3) _ <- queue.offer("A") //(1) _ <- queue.offer("B") //(2) } yield ()
  • 74.
    Dropping for { queue <-Queue.dropping[String](3) _ <- queue.offer("A") //(1) _ <- queue.offer("B") //(2) _ <- queue.offer("C") //(3) } yield ()
  • 75.
    Dropping for { queue <-Queue.dropping[String](3) _ <- queue.offer("A") //(1) _ <- queue.offer("B") //(2) _ <- queue.offer("C") //(3) _ <- queue.offer("D") //(4) } yield ()
  • 76.
    Dropping for { queue <-Queue.dropping[String](3) _ <- queue.offer("A") //(1) _ <- queue.offer("B") //(2) _ <- queue.offer("D") //(4) } yield ()
  • 77.
    Shutdown for { queue <-Queue.unbounded[String] _ <- queue.offer("A").forever.fork _ <- queue.take.forever.fork } yield ()
  • 78.
    Shutdown for { queue <-Queue.unbounded[String] _ <- queue.offer("A").forever.fork _ <- queue.take.forever.fork _ <- queue.shutdown } yield ()
  • 79.
    Shutdown for { queue <-Queue.unbounded[String] _ <- queue.offer("A").forever.fork _ <- queue.take.forever.fork _ <- queue.shutdown } yield ()
  • 80.
  • 81.
  • 82.
  • 83.