compositional i streams in scala
play

Compositional I/ Streams in Scala Rnar Bjarnason, Verizon Labs @ - PowerPoint PPT Presentation

Compositional I/ Streams in Scala Rnar Bjarnason, Verizon Labs @ runarorama QCon London, March 2016 Scalaz-Stream (FS2) F unctional S treams for S cala github.com/functional-streams-for-scala Disclaimer This library is changing.


  1. Compositional I/ Ο Streams in Scala Rúnar Bjarnason, Verizon Labs @ runarorama QCon London, March 2016

  2. Scalaz-Stream (FS2) F unctional S treams for S cala github.com/functional-streams-for-scala

  3. 
 Disclaimer This library is changing. 
 We’ll talk about the current version (0.8).

  4. Funnel — oncue.github.io/funnel http4s — http4s.org streamz — github.com/krasserm/streamz

  5. Scalaz-Stream (FS2) a purely functional streaming I/O library for Scala

  6. • Streams are essentially “lazy lists” of data and effects . • Immutable and 
 referentially transparent

  7. Design goals • compositional • expressive • resource-safe • comprehensible

  8. import scalaz.stream._ io.linesR("testdata/fahrenheit.txt") .filter(s => !s.trim.isEmpty && !s.startsWith("//")) .map(line => fahrenheitToCelsius(line.toDouble).toString) .intersperse("\n") .pipe(text.utf8Encode) .to(io.fileChunkW("testdata/celsius.txt"))

  9. Process[Task,A]

  10. scalaz.concurrent.Task • Asynchronous • Compositional • Purely functional

  11. a Task is a first-class program

  12. a Task is a list of instructions

  13. Task is a monad

  14. a Task doesn’t do anything until you call .run

  15. Constructing Tasks

  16. Task.delay(readLine): Task[String] Task.now(42): Task[Int] Task.fail( new Exception("oops!") ): Task[Nothing]

  17. a: Task[A] pool: java.util.concurrent.ExecutorService Task.fork(a)(pool): Task[A]

  18. Combining Tasks

  19. a: Task[A] b: Task[B] val c: Task[(A,B)] = Nondeterminism[Task].both(a,b)

  20. a: Task[A] f: A => Task[B] val b: Task[B] = a flatMap f

  21. val program: Task[Unit] = for { _ <- delay(println("What's your name?")) n <- delay(scala.io.StdIn.readLine) _ <- delay(println(s"Hello $n")) } yield ()

  22. Running Tasks

  23. a: Task[A] a.run: A

  24. a: Task[A] k: (Throwable \/ A) => Unit a runAsync k: Unit

  25. scalaz.stream.Process

  26. Process[F[_],A]

  27. Process[Task,A]

  28. Stream primitives val halt: Process[Nothing,Nothing] def emit[A](a: A): Process[Nothing,A] def eval[F[_],A](eff: F[A]): Process[F,A]

  29. Process.eval( Task.delay(readLine) ): Process[Task,String]

  30. def IO[A](a: => A): Process[Task,A] = Process.eval(Task.delay(a))

  31. Combining Streams

  32. p1: Process[F,A] p2: Process[F,A] val p3: Process[F,A] = p1 append p2

  33. p1: Process[F,A] p2: Process[F,A] val p3: Process[F,A] = p1 ++ p2

  34. val twoLines: Process[Task,String] = IO(readLine) ++ IO(readLine)

  35. val stdIn: Process[Task,String] = IO(readLine) ++ stdIn

  36. val stdIn: Process[Task,String] = IO(readLine).repeat

  37. val cat: Process[Task,Unit] = stdIn flatMap { s => IO(println(s)) }

  38. val cat: Process[Task,Unit] = for { s <- stdIn _ <- IO(println(s)) } yield ()

  39. def grep(r: Regex): Process[Task,Unit] = { val p = r.pattern.asPredicate.test _ def out(s: String) = IO(println(s)) stdIn filter p flatMap out }

  40. Running Processes

  41. p: Process[Task,A] p.run: Task[Unit]

  42. p: Process[Task,A] p.runLog: Task[List[A]]

  43. p: Process[F,A] B: Monoid f: A => B p runFoldMap f: F[B]

  44. F: Monad p: Process[F,A] p.run: F[Unit]

  45. Sinks

  46. x : Process[F,A] y : Sink[F,A] x to y : Process[F,Unit]

  47. import scalaz.stream.io io.stdInLines: Process[Task,String] io.stdOutLines: Sink[Task,String] val cat = io.stdInLines to io.stdOutLines

  48. A sink is just a stream of functions

  49. type Sink[F[_],A] = Process[F, A => Task[Unit]]

  50. val stdOut: Sink[Task,String] = IO { s => Task.delay(println(s)) }.repeat

  51. Pipes

  52. as: Process[F,A] p: Process1[A,B] as pipe p: Process[F,B]

  53. as: Process[F,A] val p = process1.chunk(10) as pipe p: Process[F,Vector[A]]

  54. Process.await1[A]: Process1[A,A]

  55. def take[I](n: Int): Process1[I,I] = if (n <= 0) halt else await1[I] ++ take(n - 1)

  56. def distinct[A]: Process1[A,A] = { def go(seen: Set[A]): Process1[A,A] = Process.await1[A].flatMap { a => if (seen(a)) go(seen) else Process.emit(a) ++ go(seen + a) } go(Set.empty) }

  57. Multiple sources

  58. as: Process[F,A] bs: Process[F,B] t: Tee[A,B,C] (as tee bs)(t): Process[F,C]

  59. tee.zip: Tee[A,B,(A,B)] tee.interleave: Tee[A,A,A]

  60. val add: Tee[Int,Int,Int] = { for { x <- awaitL[Int] y <- awaitR[Int] } yield x + y }.repeat val sumEach = (p1 tee p2)(add)

  61. as: Process[Task,A] bs: Process[Task,B] y: Wye[A,B,C] (as wye bs)(y): Process[Task,C]

  62. ps: Process[F,Process[F,A]] merge.mergeN(ps): Process[F,A]

  63. scalaz.stream.async

  64. Queues & Signals

  65. trait Queue[A] { ... def enqueue: Sink[Task,A] def dequeue: Process[Task,A] ... }

  66. import scalaz.stream.async._ def boundedQueue[A](n: Int): Queue[A] def unboundedQueue[A]: Queue[A] def circularBuffer[A](n: Int): Queue[A]

  67. trait Signal[A] { ... def get: Task[A] def set(a: A): Task[Unit] ... }

  68. trait Signal[A] { ... def discrete: Process[Task,A] def continuous: Process[Task,A] ... }

  69. Demo: Internet Relay Chat

  70. github.com/runarorama/ircz Server: 38 lines of Scala Client: 14 lines of Scala Uses scalaz-netty

  71. github.com/runarorama/ircz def serve(address: InetSocketAddress) = merge.mergeN { Netty serve address map { client => for { c <- client _ <- IO(clients += c.sink) _ <- c.source to messageQueue.enqueue } yield () } }

  72. github.com/runarorama/ircz val relay = for { message <- messageQueue.dequeue client <- emitAll(clients) _ <- emit(message) to client } yield ()

  73. github.com/runarorama/ircz val main = (serve wye relay)(wye.merge)

  74. github.com/runarorama/ircz client = for { c <- Netty connect Server.address in = c.source .pipe(text.utf8Decode) .to(io.stdOutLines) out = io.stdInLines .pipe(text.utf8Encode) .to(c.sink) _ <- (in wye out)(wye.merge) } yield ()

  75. github.com/functional-streams-for-scala github.com/runarorama/ircz oncue.github.io/funnel

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend