Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Scalaz Stream: Rebirth

1,114 views

Published on

Scalaz-stream introduced the Scala ecosystem to purely functional streams. Although widely deployed in production at Verizon, SlamData, and elsewhere, the last release of scalaz-stream was October 23rd, 2016, and newer projects such as FS2, Monix Iterant, and others have risen to fill the gap, each addressing different use cases in the functional programming community. In this talk, John A. De Goes, architect of the Scalaz 8 effect system, unveils a new design for a next-generation version of scalaz-stream. Designed to embrace the powerful features of the Scalaz 8 effect system—features not available in any other effect type—this design features higher-performance, stronger guarantees, and far less code than previous incarnations. You are invited to discover the practicality of functional programming, as well as its elegance, beauty, and composability, in this unique presentation available exclusively at Scale By the Bay.

Published in: Technology
  • Be the first to comment

Scalaz Stream: Rebirth

  1. 1. John A. De Goes @jdegoes - degoes.net SCALAZ STREAM REBIRTH Scale By The Bay · November 16 · San Francisco Itamar Ravid @itrvd - iravid.com
  2. 2. #ZIO #SCALEBYTHEBAY
  3. 3. PERFORMANCE OVERVIEW MOTIVATION API DESIGN
  4. 4. 1 Why Streams & Why Scalaz Stream MOTIVATION
  5. 5. Why Streams? PERFORMANCEMOTIVATION API DESIGN SUMMARY Infinite Input Sets Leak-Free Data Processing Incremental Computation ∞
  6. 6. File & Socket Processing Graph Processing Reactive & Dataflow Akka Streams FS2 Scalaz ReactiveGraphJet Why ZIO Stream? PERFORMANCEMOTIVATION API DESIGN SUMMARY
  7. 7. Why ZIO Stream? File & Socket Processing Graph Processing Reactive & Dataflow Akka Streams FS2 Scalaz ReactiveGraphJet ZIO STREAM PERFORMANCEMOTIVATION API DESIGN SUMMARY
  8. 8. Why ZIO Stream? PERFORMANCEMOTIVATION API DESIGN SUMMARY 𐄂 Cycles𐄂 Cons 𐄂 Uncons
  9. 9. ZIO Stream Old Scalaz Stream Akka Streams FS2 Lazy ✓ 𐄂 𐄂 ✓ Leak-Free ✓ 𐄂 𐄂 On a good day Uniform ✓ NA NA 𐄂 Type Inferred ✓ 𐄂 ✓ 𐄂 Economical ✓ 𐄂 𐄂 ✓ ZIO Integration ✓ 𐄂 𐄂 𐄂 PERFORMANCEMOTIVATION API DESIGN SUMMARY Why ZIO Stream?
  10. 10. 2 What Scalaz Stream Looks Like API
  11. 11. PERFORMANCEMOTIVATION API DESIGN SUMMARY AkkaStream AbruptTerminationException AbstractShape ActorAttributes ActorMaterializer ActorMaterializerSettings AmorphousShape Attributes BidiShape BindFailedException BufferOverflowException Client ClosedShape ConnectionException DelayOverflowStrategy EagerClose FanInShape FanInShape10 FanInShape11 FanInShape12 FanInShape13 FanInShape14 FanInShape15 FanInShape16 FanInShape17 FanInShape18 FanInShape19 FanInShape1N FanInShape2 FanInShape20 FanInShape21 FanInShape22 FanInShape3 FanInShape4 FanInShape5 FanInShape6 FanInShape7 FanInShape8 FanInShape9 FanOutShape FanOutShape10 FanOutShape11 FanOutShape12 FanOutShape13 FanOutShape14 FanOutShape15 FanOutShape16 FanOutShape17 FanOutShape18 FanOutShape19 FanOutShape2 FanOutShape20 FanOutShape21 FanOutShape22 FanOutShape3 FanOutShape4 FanOutShape5 FanOutShape6 FanOutShape7 FanOutShape8 FanOutShape9 FlowMonitor FlowMonitorState FlowShape Fusing Graph IgnoreBoth IgnoreCancel IgnoreComplete Inlet InPort IOResult KillSwitch KillSwitches MaterializationContext MaterializationException Materializer MaterializerLoggingProvider Outlet OutPort OverflowStrategy QueueOfferResult RateExceededException Server Shape SharedKillSwitch SinkShape SourceShape StreamLimitReachedException StreamSubscriptionTimeoutSettings StreamSubscriptionTimeoutTerminationMode StreamTcpException SubstreamCancelStrategy Supervision ThrottleMode TLSClientAuth TLSClosing TLSProtocol TLSRole UniformFanInShape UniformFanOutShape UniqueKillSwitch
  12. 12. PERFORMANCEMOTIVATION API DESIGN SUMMARY AkkaStream AbruptTerminationException AbstractShape ActorAttributes ActorMaterializer ActorMaterializerSettings AmorphousShape Attributes BidiShape BindFailedException BufferOverflowException Client ClosedShape ConnectionException DelayOverflowStrategy EagerClose FanInShape FanInShape10 FanInShape11 FanInShape12 FanInShape13 FanInShape14 FanInShape15 FanInShape16 FanInShape17 FanInShape18 FanInShape19 FanInShape1N FanInShape2 FanInShape20 FanInShape21 FanInShape22 FanInShape3 FanInShape4 FanInShape5 FanInShape6 FanInShape7 FanInShape8 FanInShape9 FanOutShape FanOutShape10 FanOutShape11 FanOutShape12 FanOutShape13 FanOutShape14 FanOutShape15 FanOutShape16 FanOutShape17 FanOutShape18 FanOutShape19 FanOutShape2 FanOutShape20 FanOutShape21 FanOutShape22 FanOutShape3 FanOutShape4 FanOutShape5 FanOutShape6 FanOutShape7 FanOutShape8 FanOutShape9 FlowMonitor FlowMonitorState FlowShape Fusing Graph IgnoreBoth IgnoreCancel IgnoreComplete Inlet InPort IOResult KillSwitch KillSwitches MaterializationContext MaterializationException Materializer MaterializerLoggingProvider Outlet OutPort OverflowStrategy QueueOfferResult RateExceededException Server Shape SharedKillSwitch SinkShape SourceShape StreamLimitReachedException StreamSubscriptionTimeoutSettings StreamSubscriptionTimeoutTerminationMode StreamTcpException SubstreamCancelStrategy Supervision ThrottleMode TLSClientAuth TLSClosing TLSProtocol TLSRole UniformFanInShape UniformFanOutShape UniqueKillSwitch
  13. 13. Stream Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY ZIO STREAM
  14. 14. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY Stream[E, A] May fail with a checked error of type E May effectfully produce zero or more values of type A
  15. 15. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY Monoid append zero Applicative map point ap Monad bind Bifunctor leftMap bimap Alternative alt empty
  16. 16. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY Stream.empty Stream.point(v) Stream.fromIterable(list) Stream.liftIO(io) Stream.fromQueue(queue) Stream.unfold(s)(f) Stream.unfoldM(s)(f) Stream.bracket(open)(close)(read) val empty: Stream[Nothing, Nothing] = Stream.empty
  17. 17. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val singleton: Stream[Nothing, Int] = Stream.point(42) Stream.empty Stream.point(v) Stream.fromIterable(list) Stream.liftIO(io) Stream.fromQueue(queue) Stream.unfold(s)(f) Stream.unfoldM(s)(f) Stream.bracket(open)(close)(read)
  18. 18. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val hundred: Stream[Nothing, Int] = Stream.fromIterable(0 to 100) Stream.empty Stream.point(v) Stream.fromIterable(list) Stream.liftIO(io) Stream.fromQueue(queue) Stream.unfold(s)(f) Stream.unfoldM(s)(f) Stream.bracket(open)(close)(read)
  19. 19. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val userIn: Stream[IOException, String] = Stream.liftIO(getStrLn) Stream.empty Stream.point(v) Stream.fromIterable(list) Stream.liftIO(io) Stream.fromQueue(queue) Stream.unfold(s)(f) Stream.unfoldM(s)(f) Stream.bracket(open)(close)(read)
  20. 20. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val intQueue: Queue[Int] = ... val intStream: Stream[Nothing, Int] = Stream.fromQueue(intQueue) Stream.empty Stream.point(v) Stream.fromIterable(list) Stream.liftIO(io) Stream.fromQueue(queue) Stream.unfold(s)(f) Stream.unfoldM(s)(f) Stream.bracket(open)(close)(read)
  21. 21. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val integers: Stream[Nothing, Int] = Stream.unfold(0)(i => (i, i + 1)) Stream.empty Stream.point(v) Stream.fromIterable(list) Stream.liftIO(io) Stream.fromQueue(queue) Stream.unfold(s)(f) Stream.unfoldM(s)(f) Stream.bracket(open)(close)(read)
  22. 22. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val latency: Stream[Nothing, Long] = Stream.unfoldM(0 -> 0) { case (n, total) => api.measureLatency(l => (n + 1) -> (total + n)) } Stream.empty Stream.point(v) Stream.fromIterable(list) Stream.liftIO(io) Stream.fromQueue(queue) Stream.unfold(s)(f) Stream.unfoldM(s)(f) Stream.bracket(open)(close)(read)
  23. 23. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val fileBytes: Stream[IOException, Byte] = Stream.bracket(openFile)(closeFile(_)) { file => file.readByte.attempt.toOption } Stream.empty Stream.point(v) Stream.fromIterable(list) Stream.liftIO(io) Stream.fromQueue(queue) Stream.unfold(s)(f) Stream.unfoldM(s)(f) Stream.bracket(open)(close)(read)
  24. 24. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val integers: Stream[Nothing, Int] = Stream.unfold(0)(i => (i, i + 1)) val integerDigits: Stream[Nothing, Int] = integers.map(_.toString).map(_.length) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  25. 25. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val users: Stream[Exception, User] = ... val usersWithProfile: Stream[Exception, (User, Profile)] = for { user <- users prof <- Stream.liftIO(getProfile(user.id)) } yield (user, prof) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  26. 26. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val usersWithProfile: Stream[Exception, (User, Profile)] = … val targetUsers: Stream[Exception, User] = usersWithProfile.filter(user => user.age >= 18 && user.age <= 32 && user.city == "San Francisco" && user.interests.contains("technology")) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  27. 27. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY type File = Stream[IOException, Report] val monthlyFiles: List[File] = … val allFiles = monthlyFiles.foldLeft[File] (Stream.empty)(_ ++ _) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  28. 28. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val stream: Stream[IOException, Chunk[Byte]] = Stream.bracket(openFile)( closeFile)(readChunk) val usersJ: Stream[IOException, Json] = stream.transduce(toJson) .filter(isUserRecord) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  29. 29. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val integers: Stream[Nothing, Int] = Stream.unfold(0)(i => (i, i + 1)) val averages: Stream[Nothing, Int] = integers.scan(0 -> 0) { case ((sum, count), int) => (sum + int, count + 1) -> if (count == 0) Int.MaxValue else sum / count } stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  30. 30. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val integers: Stream[Nothing, Int] = Stream.unfold(0)(i => (i, i + 1)) val first100Evens: Stream[Nothing, Int] = integers.filter(_ % 2 == 0).take(100) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  31. 31. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val integers: Stream[Nothing, Int] = Stream.unfold(0)(i => (i, i + 1)) val evensUnder100: Stream[Nothing, Int] = integers.filter(_ % 2 == 0) .takeWhile(_ < 100) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  32. 32. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val integers: Stream[Nothing, Int] = Stream.unfold(0)(i => (i, i + 1)) val evensAfter100: Stream[Nothing, Int] = integers.filter(_ % 2 == 0).drop(100) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  33. 33. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val integers: Stream[Nothing, Int] = Stream.unfold(0)(i => (i, i + 1)) val evensOver100: Stream[Nothing, Int] = integers.filter(_ % 2 == 0) .dropWhile(_ < 100) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  34. 34. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val inputs: Stream[IOException, String] = Stream.liftIO(getStrLn).forever val echo: IO[IOException, Unit] = inputs.foreach(putStrLn) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  35. 35. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val integers: Stream[Nothing, Int] = Stream.unfold(0)(i => (i, i + 1)) val users: Stream[Exception, User] = … val usersWithId: Stream[Exception, (Int, User)] = integers.zip(users) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  36. 36. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val stream1: Stream[IOException, JSON] = kafka.stream("events1") val stream2: Stream[IOException, JSON] = kafka.stream("events2") val both: Stream[IOException, JSON] = stream1.merge(stream2) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  37. 37. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY val file1: Stream[IOException, User] = readFile("file1.data") .transduce(toUser) val file2: Stream[IOException, User] = readFile("file2.data") .transduce(toUser) val fastest: Stream[IOException, User] = file1.joinWith(file2)(_ race _) stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  38. 38. Stream PERFORMANCEMOTIVATION API DESIGN SUMMARY type StreamIO[A] = Stream[IOException, A] val bytes: StreamIO[Byte] = … val headersAndContent: Managed[IOException, (ContentType, StreamIO[Byte])] = bytes.peel(parseContentType) headersAndContent.use { case (ContentType(Json), content) => content.transduce(toJson)... case (ContentType(Xml), content) => content.transduce(toXml)... } stream.map(f) stream.flatMap(f) stream.filter(f) stream1 ++ stream2 stream.transduce(what) stream.scan(z)(f) stream.take(n) stream.takeWhile(f) stream.drop(n) stream.dropWhile(f) stream.foreach(f) stream1.zip(stream2) stream1.merge(stream2) stream1.joinWith(stream2)(f) stream.peel(what)
  39. 39. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY Sink[E, A0, A, B] May fail with a checked error of type E May effectfully produce a result of type B Consumes values of type A May possibly output a remainder of type A0
  40. 40. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY trait Stream[E, A] { def run[R](sink: Sink[E, A, A, R]): IO[E, R] } myStream.run(Sink.drain) // IO[E, Unit] myStream.run(decodeRequest) // IO[E, Request] myStream.run(Sink.collect) // IO[E, List[A]]
  41. 41. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY Monoid append zero Applicative map point ap Monad bind Bifunctor leftMap bimap Alternative alt empty Category id compose Profunctor lmap rmap dimap Strong first second Choice left right
  42. 42. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val answer: Sink[Nothing, Nothing, Any, Int] = Sink.point(42) Sink.point(value) Sink.liftIO(ioValue) Sink.lift(f) Sink.fail(e) Sink.await Sink.drain Sink.collect Sink.fold(init)(step)
  43. 43. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val lifted: Sink[Throwable, Nothing, Any, Array[Byte]] = Sink.liftIO(IO.syncThrowable(dangerousOp)) Sink.point(value) Sink.liftIO(ioValue) Sink.lift(f) Sink.fail(e) Sink.await Sink.drain Sink.collect Sink.fold(init)(step)
  44. 44. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val squared: Sink[Unit, Nothing, Int, Int] = Sink.lift(i => i * i) Sink.point(value) Sink.liftIO(ioValue) Sink.lift(f) Sink.fail(e) Sink.await Sink.drain Sink.collect Sink.fold(init)(step)
  45. 45. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val failure: Sink[DomainError, Nothing, Any, Nothing] = Sink.fail(BadOperation) Sink.point(value) Sink.liftIO(ioValue) Sink.lift(f) Sink.fail(e) Sink.await Sink.drain Sink.collect Sink.fold(init)(step)
  46. 46. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val json: Sink[Unit, Nothing, Json, Json] = Sink.await Sink.point(value) Sink.liftIO(ioValue) Sink.lift(f) Sink.fail(e) Sink.await Sink.drain Sink.collect Sink.fold(init)(step)
  47. 47. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val drain: Sink[Nothing, Nothing, Any, Unit] = Sink.drain Sink.point(value) Sink.liftIO(ioValue) Sink.lift(f) Sink.fail(e) Sink.await Sink.drain Sink.collect Sink.fold(init)(step)
  48. 48. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val collected: Sink[Nothing, Nothing, Json, List[Json]] = Sink.collect[Json] Sink.point(value) Sink.liftIO(ioValue) Sink.lift(f) Sink.fail(e) Sink.await Sink.drain Sink.collect Sink.fold(init)(step)
  49. 49. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val parser: Sink[Nothing, Char, Char, Either[Error, Int]] = Sink.fold((ParserState.initial, List[Int]()) { case (ParserState.Digits, c) if c.isDigit => // ... } Sink.point(value) Sink.liftIO(ioValue) Sink.lift(f) Sink.fail(e) Sink.await Sink.drain Sink.collect Sink.fold(init)(step)
  50. 50. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val digits: Sink[Nothing, Char, Char, List[Char]] = Sink.readWhile[Char](_.isDigit) val number: Sink[Nothing, Char, Char, Int] = Sink.map(_.mkString.toInt) sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  51. 51. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val summing: Sink[Nothing, Int, Int, Int] = Sink.fold(0)(_ + _) case class Person(name: String, salary: Int) val salarySum: Sink[Nothing, Int, Person, Int] = Sink.contramap[Person](_.salary) sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  52. 52. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val err: Sink[DomainError, Nothing, Any, Nothing] = Sink.fail(DomainError) val errs: Sink[AppError, Nothing, Any, Nothing] = Sink.mapError(AppError(_)) sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  53. 53. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val sumOfConsecutive: Sink[Nothing, Nothing, Int, Int] = for { a <- Sink.await b <- Sink.await } yield a + b sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  54. 54. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val parseHeader: Sink[Err, Byte, Byte, Header] = … val parseBody: Sink[Err, Byte, Byte, Body] = … val parseHeaderAndBody: Sink[Err, Byte, Byte, (Header, Body)] = parseHeader ~ parseBody sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  55. 55. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val parseHeader: Sink[Err, Byte, Byte, Header] = … val maybeParseHeader: Sink[Nothing, Byte, Byte, Option[Header]] = parseHeader ? sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  56. 56. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val request1: Sink[Err, Byte, Byte, Req1] = … val request2: Sink[Err, Byte, Byte, Req2] = … val request: Sink[Err, Byte, Byte, Either[Req1, Req2]] = request1 raceBoth request2 sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  57. 57. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val request1: Sink[Err, Byte, Byte, Req1] = … val request2: Sink[Err, Byte, Byte, Req2] = … val request: Sink[Err, Byte, Byte, Either[Req1, Req2]] = request1 orElse request2 sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  58. 58. Sink PERFORMANCEMOTIVATION API DESIGN SUMMARY val parseUser: Sink[Err, Byte, Byte, Person] = … val parsePeople: Sink[Err, Byte, Byte, List[Person]] = parseUser repeat sink.map(f) sink.contramap(f) sink.mapError(f) sink.flatMap(f) sink ~ otherSink sink.? sink.raceBoth(other) sink.orElse(other) sink.repeat
  59. 59. 3 How Fast Is Scalaz Stream PERFORMANCE
  60. 60. Filter · Map · Sum PERFORMANCEMOTIVATION API DESIGN SUMMARY Start with stream of integers (chunked) Filter for only even integers Convert to longs Sum all integers
  61. 61. Filter · Map · Sum PERFORMANCEMOTIVATION API DESIGN SUMMARY def akkaChunkFilterMapSum = { val chunks = (1 to chunkCount).flatMap(i => Array.fill(chunkSize)(i)) val program = AkkaSource .fromIterator(() => chunks.iterator) .filter(_ % 2 == 0) .map(_.toLong) .toMat(AkkaSink.fold(0L)(_ + _))(Keep.right) Await.result(program.run, Duration.Inf) }
  62. 62. Filter · Map · Sum PERFORMANCEMOTIVATION API DESIGN SUMMARY
  63. 63. Filter · Map · Sum PERFORMANCEMOTIVATION API DESIGN SUMMARY def fs2ChunkFilterMapSum = { val chunks = (1 to chunkCount).map(i => FS2Chunk.array(Array.fill(chunkSize)(i))) val stream = FS2Stream(chunks: _*) .flatMap(FS2Stream.chunk(_)) .filter(_ % 2 == 0) .map(_.toLong) .covary[CatsIO] .compile .fold(0L)(_ + _) stream.unsafeRunSync }
  64. 64. Filter · Map · Sum PERFORMANCEMOTIVATION API DESIGN SUMMARY FS2
  65. 65. Filter · Map · Sum PERFORMANCEMOTIVATION API DESIGN SUMMARY def scalazChunkFilterMapSum = { val chunks = (1 to chunkCount).map(i => Chunk.fromArray(Array.fill(chunkSize)(i))) val stream = StreamChunk .fromChunks(chunks: _*) .filter(_ % 2 == 0) .map(_.toLong) val sink = Sink.foldLeft(0L)((s, c) => c.foldl(s)(_ + _)) unsafeRun(stream.run(sink)) }
  66. 66. Filter · Map · Sum PERFORMANCEMOTIVATION API DESIGN SUMMARY FS2
  67. 67. CSV Tokenize PERFORMANCEMOTIVATION API DESIGN SUMMARY Start with stream of characters (chunked) Identify CSV separators and columns Convert character stream into token stream
  68. 68. CSV Tokenize PERFORMANCEMOTIVATION API DESIGN SUMMARY def akkaCsvTokenize() = { val chunks = genCsvChunks val program = AkkaSource .fromIterator(() => chunks.flatten.iterator) .scan((Vector.empty[Char], Vector.empty[CSV.Token])) { case ((acc, _), char) => if (char == CSV.ColumnSep) { Vector.empty[Char] -> ((if (acc.length > 0) Vector(CSV.Column(acc.mkString)) else Vector.empty[CSV.Token]) ++ Vector(CSV.NewCol)) } else if (char == CSV.RowSep) { Vector.empty[Char] -> ((if (acc.length > 0) Vector(CSV.Column(acc.mkString)) else Vector.empty[CSV.Token]) ++ Vector(CSV.NewCol)) } else (acc :+ char) -> Vector.empty[CSV.Token] } .flatMapConcat(t => AkkaSource(t._2)) .toMat(AkkaSink.ignore)(Keep.right) Await.result(program.run, Duration.Inf) }
  69. 69. CSV Tokenize PERFORMANCEMOTIVATION API DESIGN SUMMARY
  70. 70. CSV Tokenize PERFORMANCEMOTIVATION API DESIGN SUMMARY def fs2CsvTokenize() = { val chunks = genCsvChunks.map(FS2Chunk.array(_)) val stream = FS2Stream(chunks: _*) .flatMap(FS2Stream.chunk(_)) .scan((Vector.empty[Char], Vector.empty[CSV.Token])) { case ((acc, _), char) => if (char == CSV.ColumnSep) { Vector.empty[Char] -> ((if (acc.length > 0) Vector(CSV.Column(acc.mkString)) else Vector.empty[CSV.Token]) ++ Vector(CSV.NewCol)) } else if (char == CSV.RowSep) { Vector.empty[Char] -> ((if (acc.length > 0) Vector(CSV.Column(acc.mkString)) else Vector.empty[CSV.Token]) ++ Vector(CSV.NewCol)) } else (acc :+ char) -> Vector.empty[CSV.Token] } .flatMap(t => FS2Stream(t._2)) .covary[CatsIO] .compile .drain stream.unsafeRunSync }
  71. 71. CSV Tokenize PERFORMANCEMOTIVATION API DESIGN SUMMARY FS2
  72. 72. CSV Tokenize PERFORMANCEMOTIVATION API DESIGN SUMMARY def scalazCsvTokenize() = { val chunks = genCsvChunks.map(Chunk.fromArray(_)) val stream = ChunkedStream .fromChunks(chunks: _*) .scan[Vector[Char], Chunk[CSV.Token]](Vector.empty[Char]) { case (acc, char) => if (char == CSV.ColumnSep) { Vector.empty[Char] -> ((if (acc.length > 0) Chunk(CSV.Column(acc.mkString)) else Chunk.empty) ++ Chunk(CSV.NewCol)) } else if (char == CSV.RowSep) { Vector.empty[Char] -> ((if (acc.length > 0) Chunk(CSV.Column(acc.mkString)) else Chunk.empty) ++ Chunk(CSV.NewCol)) } else (acc :+ char) -> Chunk.empty } .mapConcat(identity(_)) unsafeRun(stream.run(Sink.drain)) }
  73. 73. CSV Tokenize PERFORMANCEMOTIVATION API DESIGN SUMMARY FS2
  74. 74. 4 The Inner Workings of Scalaz Stream DESIGN
  75. 75. BUILD YOUR OWN STREAM Initial Encoding PERFORMANCEMOTIVATION API DESIGN SUMMARY
  76. 76. Initial Encoding sealed trait Stream[+A] Type Emission Mapping Joining Merging Folding Effect ... PERFORMANCEMOTIVATION API DESIGN SUMMARY
  77. 77. Initial Encoding sealed trait Stream[+A] case class Emit[A](a: A) extends Stream[A] PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  78. 78. Initial Encoding sealed trait Stream[+A] case class Emit[A](a: A) extends Stream[A] case class Map[A0, A](s: Stream[A0], f: A0 => A) extends Stream[A] PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  79. 79. Initial Encoding sealed trait Stream[+A] case class Emit[A](a: A) extends Stream[A] case class Map[A0, A](s: Stream[A0], f: A0 => A) extends Stream[A] case class Join[A](s: Stream[Stream[A]]) extends Stream[A] PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  80. 80. Initial Encoding sealed trait Stream[+A] case class Emit[A](a: A) extends Stream[A] case class Map[A0, A](s: Stream[A0], f: A0 => A) extends Stream[A] case class Join[A](s: Stream[Stream[A]]) extends Stream[A] case class Merge[A](l: Stream[A], r: Stream[A]) extends Stream[A] PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  81. 81. Initial Encoding sealed trait Stream[+A] case class Emit[A](a: A) extends Stream[A] case class Map[A0, A](s: Stream[A0], f: A0 => A) extends Stream[A] case class Join[A](s: Stream[Stream[A]]) extends Stream[A] case class Merge[A](l: Stream[A], r: Stream[A]) extends Stream[A] case class Fold[A0, A](a: A, s: Stream[A0], f: (A, A0) => A) extends Stream[A] PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  82. 82. Initial Encoding PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ... sealed trait Stream[+A] case class Emit[A](a: A) extends Stream[A] case class Map[A0, A](s: Stream[A0], f: A0 => A) extends Stream[A] case class Join[A](s: Stream[Stream[A]]) extends Stream[A] case class Merge[A](l: Stream[A], r: Stream[A]) extends Stream[A] case class Fold[A0, A](a: A, s: Stream[A0], f: (A, A0) => A) extends Stream[A] case class Effect[A](io: IO[A]) extends Stream[A]
  83. 83. Initial Encoding def drain[A](s: Stream[A]): IO[Unit] = s match { case Emit(a) => … ... } Interpreter PERFORMANCEMOTIVATION API DESIGN SUMMARY
  84. 84. BUILD YOUR OWN STREAM Final Encoding PERFORMANCEMOTIVATION API DESIGN SUMMARY
  85. 85. Final Encoding case class Stream[+A]( run: (A => IO[Unit]) => IO[Unit]) PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  86. 86. Final Encoding case class Stream[+A]( run: (A => IO[Unit]) => IO[Unit]) object Stream { def emit[A](a: => A): Stream[A] = Stream[A](read => read(a)) } PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  87. 87. Final Encoding case class Stream[+A]( run: (A => IO[Unit]) => IO[Unit]) { def map[B](f: A => B): Stream[B] = Stream(r => run(r.compose(f))) } object Stream { def emit[A](a: => A): Stream[A] = Stream[A](read => read(a)) } PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  88. 88. Final Encoding case class Stream[+A]( run: (A => IO[Unit]) => IO[Unit]) { def map[B](f: A => B): Stream[B] = Stream(r => run(r.compose(f))) } object Stream { def emit[A](a: => A): Stream[A] = Stream[A](read => read(a)) def join[A](s: Stream[Stream[A]]) = Stream(r => s.run(sa => sa.run(r))) } PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  89. 89. Final Encoding case class Stream[+A]( run: (A => IO[Unit]) => IO[Unit]) { def map[B](f: A => B): Stream[B] = Stream(r => run(r.compose(f))) def merge[A1 >: A](that: Stream[A1]) = Stream[A1](r => run(r).par(that.run(r)).void) } object Stream { def emit[A](a: => A): Stream[A] = Stream[A](read => read(a)) def join[A](s: Stream[Stream[A]]) = Stream(r => s.run(sa => sa.run(r))) } PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  90. 90. Final Encoding case class Stream[+A]( run: (A => IO[Unit]) => IO[Unit]) { def map[B](f: A => B): Stream[B] = Stream(r => run(r.compose(f))) def merge[A1 >: A](that: Stream[A1]) = Stream[A1](r => run(r).par(that.run(r)).void) def fold[S](s: S)(f: (S, A) => S) = ... } object Stream { def emit[A](a: => A): Stream[A] = Stream[A](read => read(a)) def join[A](s: Stream[Stream[A]]) = Stream(r => s.run(sa => sa.run(r))) } PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  91. 91. Final Encoding case class Stream[+A]( run: (A => IO[Unit]) => IO[Unit]) { def map[B](f: A => B): Stream[B] = Stream(r => run(r.compose(f))) def merge[A1 >: A](that: Stream[A1]) = Stream[A1](r => run(r).par(that.run(r)).void) def fold[S](s: S)(f: (S, A) => S) = ... } object Stream { def emit[A](a: => A): Stream[A] = Stream[A](read => read(a)) def join[A](s: Stream[Stream[A]]) = Stream(r => s.run(sa => sa.run(r))) def liftIO[A](io: IO[A]): Stream[A] = Stream[A](io.flatMap(_)) } PERFORMANCEMOTIVATION API DESIGN SUMMARY Type Emission Mapping Joining Merging Folding Effect ...
  92. 92. Final Flexible Lookahead optimizations Ad Hoc Non-uniform Initial Initial vs Final ✓ ✓ 𐄂 PERFORMANCEMOTIVATION API DESIGN SUMMARY 𐄂 Inflexible No lookahead optimizations Structured Uniform 𐄂 𐄂 ✓ ✓
  93. 93. Constant space processing Discovered in 2003 Aggressively lazy ITERATEES PERFORMANCEMOTIVATION API DESIGN SUMMARY Final encoding-friendly Automatically leak-free “Left folds”
  94. 94. Iteratees 101 sealed trait Iteratee[-A, +B] case class More[A, B](f: A => Iteratee[A, B]) extends Iteratee[A, B] case class Done[B](value: B) extends Iteratee[Any, B] sealed trait Enumerator[+A] { self => def run[A1 >: A, B](iteratee: Iteratee[A1, B]): IO[B] } PERFORMANCEMOTIVATION API DESIGN SUMMARY
  95. 95. Iteratees 101 sealed trait Enumerator[+A] { self => final def run[A1 >: A, B](iteratee: Iteratee[A1, B]): IO[B] = fold(...)(...) def fold[B, S](s: S)(f: (S, A) => Either[S, B]): IO[B] } PERFORMANCEMOTIVATION API DESIGN SUMMARY
  96. 96. Iteratees 101 sealed trait Enumerator[+A] { self => final def run[A1 >: A, B](iteratee: Iteratee[A1, B]): IO[B] = fold(...)(...) def fold[B, S](s: S)(f: (S, A) => Either[S, B]): IO[B] final def map[B](f0: A => B): Enumerator[B] = new Enumerator[B] { def fold[C, S](s: S)(f: (S, B) => Either[S, C]): IO[C] = self.fold(s)((s, a) => f(s, f0(a))) } } PERFORMANCEMOTIVATION API DESIGN SUMMARY
  97. 97. Iteratees 101 sealed trait Enumerator[+A] { self => final def run[A1 >: A, B](iteratee: Iteratee[A1, B]): IO[B] = fold(...)(...) def fold[B, S](s: S)(f: (S, A) => Either[S, B]): IO[B] final def map[B](f0: A => B): Enumerator[B] = new Enumerator[B] { def fold[C, S](s: S)(f: (S, B) => Either[S, C]): IO[C] = self.fold(s)((s, a) => f(s, f0(a))) } final def filter(f0: A => Boolean): Enumerator[A] = new Enumerator[A] { def fold[B, S](s: S)(f: (S, A) => Either[S, B]): IO[B] = self.fold(s)((s, a) => if (f0(a)) f(s, a) else Left(s)) } } PERFORMANCEMOTIVATION API DESIGN SUMMARY
  98. 98. Iteratees 101 𐄂 Stack Safe𐄂 Combining 𐄂 Leftovers PERFORMANCEMOTIVATION API DESIGN SUMMARY
  99. 99. Iteratees 101 𐄂 Stack Safe?𐄂 Combining? 𐄂 Leftovers? PERFORMANCEMOTIVATION API DESIGN SUMMARY
  100. 100. Iteratees 101 PERFORMANCEMOTIVATION API DESIGN SUMMARY
  101. 101. Iteratees 101 PERFORMANCEMOTIVATION API DESIGN SUMMARY
  102. 102. Iteratees 101 PERFORMANCEMOTIVATION API DESIGN SUMMARY
  103. 103. Iteratees 101 sealed trait IterateeT[F[_], -A, +B] case class More[F[_], A, B](f: A => IterateeT[F, A, B]) extends IterateeT[F, A, B] case class Done[F[_], B](value: B) extends IterateeT[F, Any, B] case class Effect[F[_], B](fx: F[B]) extends IterateeT[F, Any, B] PERFORMANCEMOTIVATION API DESIGN SUMMARY
  104. 104. Iteratees 101 sealed trait IterateeT[F[_], -A, +B] case class More[F[_], A, B](f: A => IterateeT[F, A, B]) extends IterateeT[F, A, B] case class Done[F[_], B](value: B) extends IterateeT[F, Any, B] case class Effect[F[_], B](fx: F[B]) extends IterateeT[F, Any, B] type Parallel[F[_], A1, A2, B] = IterateeT[IterateeT[F, A1, ?], A2, B] def lift[F[_], A1, A2, B](it: IterateeT[F, A1, B]): Parallel[F, A1, A2, B] = Effect[IterateeT[F, A1, ?], B](it) PERFORMANCEMOTIVATION API DESIGN SUMMARY
  105. 105. Iteratees 101 sealed trait IterateeT[F[_], -A, +B] case class More[F[_], A, B](f: A => IterateeT[F, A, B]) extends IterateeT[F, A, B] case class Done[F[_], B](value: B) extends IterateeT[F, Any, B] case class Effect[F[_], B](fx: F[B]) extends IterateeT[F, Any, B] type Parallel[F[_], A1, A2, B] = IterateeT[IterateeT[F, A1, ?], A2, B] def lift[F[_], A1, A2, B](it: IterateeT[F, A1, B]): Parallel[F, A1, A2, B] = Effect[IterateeT[F, A1, ?], B](it) def readLeft[F[_], A1, A2]: Parallel[F, A1, A2, A1] = lift(More(a => Done(a))) def readRight[F[_], A1, A2]: Parallel[F, A1, A2, A2] = More(a => Done(a)) PERFORMANCEMOTIVATION API DESIGN SUMMARY
  106. 106. Iteratees 101 sealed trait IterateeT[F[_], -A, +B] case class More[F[_], A, B](f: A => IterateeT[F, A, B]) extends IterateeT[F, A, B] case class Done[F[_], B](value: B) extends IterateeT[F, Any, B] case class Effect[F[_], B](fx: F[B]) extends IterateeT[F, Any, B] type Parallel[F[_], A1, A2, B] = IterateeT[IterateeT[F, A1, ?], A2, B] def lift[F[_], A1, A2, B](it: IterateeT[F, A1, B]): Parallel[F, A1, A2, B] = Effect[IterateeT[F, A1, ?], B](it) def readLeft[F[_], A1, A2]: Parallel[F, A1, A2, A1] = lift(More(a => Done(a))) def readRight[F[_], A1, A2]: Parallel[F, A1, A2, A2] = More(a => Done(a)) PERFORMANCEMOTIVATION API DESIGN SUMMARY
  107. 107. ZIO Stream trait Stream[E, A] { def fold[S](s: S)(f: (S, A) => IO[E, Step[S]]): IO[E, Step[S]] } object Stream { sealed trait Step[S] object Step { case class Stop[S](value: S) extends Step[S] case class Cont[S](value: S) extends Step[S] } } PERFORMANCEMOTIVATION API DESIGN SUMMARY
  108. 108. ZIO Stream trait Stream[E, A] { def fold[S](s: S)(f: (S, A) => IO[E, Step[S]]): IO[E, Step[S]] } object Stream { sealed trait Step[S] object Step { case class Stop[S](value: S) extends Step[S] case class Cont[S](value: S) extends Step[S] } } Continuation Monad! PERFORMANCEMOTIVATION API DESIGN SUMMARY
  109. 109. ZIO Stream trait Stream[E, A] { def fold[S](s: S)(f: (S, A) => IO[E, Step[S]]): IO[E, Step[S]] def toQueue(capacity: Int = 1): Managed[Nothing, Queue[Take[E, A]]] = for { queue <- Managed.liftIO(Queue.bounded[Take[E, A]](capacity)) offerVal = (a: A) => queue.offer(Take.Value(a)).void offerErr = (e: E) => queue.offer(Take.Fail(e)) enqueuer = (self.foreach[E, A](offerVal).catchAll(offerErr) *> queue.offer(Take.End).forever).fork _ <- Managed(enqueuer)(_.interrupt) } yield queue } PERFORMANCEMOTIVATION API DESIGN SUMMARY
  110. 110. ZIO Stream trait Stream[E, A] { def fold[S](s: S)(f: (S, A) => IO[E, Step[S]]): IO[E, Step[S]] def zip[B, C](that: Stream[E, B]): Stream[E, (A, B)] = new Stream[E, (A, B)] { type Q[A] = Queue[Take[E, A]] def fold[S](s: S)(f: (S, (A, B)) => IO[E, Step[S]]): IO[E, Step[S]] = { def loop(q1: Q[A], q2: Q[B], s: S): IO[E, Step[S]] = Take.option(q1.take).seq(Take.option(q2.take)).flatMap { case (Some(a), Some(b)) => f(s, (a, b)) case _ => IO.now(Step.Cont(s)) } self.toQueue().use(q1 => that.toQueue().use(q2 => loop(q1, q2, s))) } } } PERFORMANCEMOTIVATION API DESIGN SUMMARY
  111. 111. ZIO Stream 𐄂 Stack Safe✓ Combining 𐄂 Leftovers PERFORMANCEMOTIVATION API DESIGN SUMMARY
  112. 112. ZIO Stream trait Stream[E, A] { def fold[S](s: S)(f: (S, A) => IO[E, Step[S]]): IO[E, Step[S]] def peel[R](sink: Sink[E, A, A, R]): Managed[E, (R, Stream[E, A])] = ... } Compose all leading sinks Peel off sink (e.g. headers) Work with stream remainder PERFORMANCEMOTIVATION API DESIGN SUMMARY
  113. 113. ZIO Stream 𐄂 Stack Safe✓ Combining ✓ Leftovers PERFORMANCEMOTIVATION API DESIGN SUMMARY
  114. 114. ZIO Stream trait Stream[E, A] { def fold[S]: IO[Nothing, (S, (S, A) => IO[E, Step[S]]) => IO[E, Step[S]]] // trampolined: F[A => F[B]] } PERFORMANCEMOTIVATION API DESIGN SUMMARY
  115. 115. ZIO Stream ✓ Stack Safe✓ Combining ✓ Leftovers PERFORMANCEMOTIVATION API DESIGN SUMMARY
  116. 116. 5 Where To From Here SUMMARY
  117. 117. Fusion, Queue & complex combinators Performance Outstanding Work Comprehensive test suites and great docs Tests & Docs Combinators for every reason Combinators PERFORMANCEMOTIVATION API DESIGN SUMMARY
  118. 118. Eric Torreborre — Beautiful Folds The FS2 team — Michael Pilquist, Fabio Labella, Pavel Chlupacek, et al Special thanks to all people who made ZIO Stream possible. Credits Oleg Kiselyov — Iteratees 2003 PERFORMANCEMOTIVATION API DESIGN SUMMARY
  119. 119. Any questions? Thanks! John A. De Goes @jdegoes - degoes.net Itamar Ravid @itrvd - iravid.com PERFORMANCEMOTIVATION API DESIGN SUMMARY

×