Diese Präsentation wurde erfolgreich gemeldet.

Streams for (Co)Free!

5

Teilen

1 von 35
1 von 35

Streams for (Co)Free!

5

Teilen

Herunterladen, um offline zu lesen

There are many popular stream libraries for Scala developers, including Akka Streams, scalaz-stream, fs2, plus others in the Java ecosystem. While all excellent choices for building reactive Scala applications, their reliance on effects makes them particularly difficult to test and reason about. In this talk, long-time Scala functional programmer John A. De Goes takes to the stage to demonstrate a new approach to modeling streams that requires less machinery and has more reasoning power, composability, flexibility, and testability than many other approaches. By attending the talk, you'll learn how the best stream library may be the one you get for (co)free!

There are many popular stream libraries for Scala developers, including Akka Streams, scalaz-stream, fs2, plus others in the Java ecosystem. While all excellent choices for building reactive Scala applications, their reliance on effects makes them particularly difficult to test and reason about. In this talk, long-time Scala functional programmer John A. De Goes takes to the stage to demonstrate a new approach to modeling streams that requires less machinery and has more reasoning power, composability, flexibility, and testability than many other approaches. By attending the talk, you'll learn how the best stream library may be the one you get for (co)free!

Weitere Verwandte Inhalte

Ähnliche Bücher

Kostenlos mit einer 30-tägigen Testversion von Scribd

Alle anzeigen

Ähnliche Hörbücher

Kostenlos mit einer 30-tägigen Testversion von Scribd

Alle anzeigen

Streams for (Co)Free!

  1. 1. Streams for (Co)Free!JohnA. De Goes — @jdegoes
  2. 2. Agenda » Induction/Coinduction » Universality of Streams » Cofree: A Principled Stream » Challenge
  3. 3. InductionTear downastructureto culminate in aterminalvalue.
  4. 4. Inductive Programs Examples » Parse a config file » Sort a list » Send an HTTP response » Compute the millionth digit of pi
  5. 5. Surprise! Most(?)BusinessProblemsAre Coinductive
  6. 6. CoinductionStartfroman initialvalueto build up an infinite structure.
  7. 7. Coinductive Processes Examples » Produce the next state of the UI given a user- input » Produce current state of config given update to config » Transform stream of requests to responses » Produce (all) the digits of pi
  8. 8. Programming Languages Hate Coinduction But"Reactive"and "Streams"
  9. 9. ByAnyOther Name Astream isamainstream example ofacoinductive process. » Data processing » Web servers » User-interfaces » Discrete "FRP" » So much more...
  10. 10. Streams ✓ Stateful ✓ Incremental computation ✓ Non-termination ✓ Consume & Emit
  11. 11. Streams Choices, Choices » Akka Streams » Java Streams » Scalaz-Streams » FS2 » Big Data: Spark, Flink, Pachyderm, Kafka, ad infinitum...
  12. 12. John's Laws ofClean FunctionalCode 1.Reasonability is directly proportional to totality & referential-transparency. 2.Composability is inversely proportional to number of data types. 3.Obfuscation is directly proportional to number of lawless interfaces. 4.Correctness is directly proportional to degree of polymorphism. 5.Shoddiness is directly proportional to encapsulation. 6.Volume is inversely proportional to orthogonality.
  13. 13. AkkaStream akka.stream 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
  14. 14. WhatCan Save Us?!? John's Laws ofClean FunctionalCode 1.Reasonability is directly proportional to totality & referential-transparency. 2.Composability is inversely proportional to number of data types. 3.Obfuscation is directly proportional to number of lawless interfaces. 4.Correctness is directly proportional to degree of polymorphism. 5.Shoddiness is directly proportional to encapsulation. 6.Volume is inversely proportional to orthogonality.
  15. 15. CofreeALLTHE POWER OFFREE, NOWWITH STREAMING!!!
  16. 16. Cofree Huh? // For Functor `F` final case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]])
  17. 17. Cofree:Take 1Cofree[F,A] isacoinductive process thatgenerates A's using effect F.
  18. 18. Cofree:Take 2Cofree[F,A] isacurrentposition A ona landscapethatrequires effect Fto movetoanewposition.
  19. 19. Cofree Comonad Methods » Where am I? def extract(f: Cofree[F, A]): A » Terraform! def extend(f: Cofree[F, A] => B): Cofree[F, B] » Plus Functor!
  20. 20. Cofree Fibs final case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]]) // final case class Name[A](run: => A) val fibs: Cofree[Name, Int] = { def unfold(prev1: Int, prev2: Int): Cofree[Name, Int] = Cofree(prev1 + prev2, Name(unfold(prev2, prev1 + prev2))) unfold(0, 1) }
  21. 21. Cofree Append def append[F[_]: ApplicativePlus, A](c1: Cofree[F, A], c2: Cofree[F, A]): Cofree[F, A] = Cofree(c1.head, c1.tail.map(t => append(t, c2)) <+> c2.point[F])
  22. 22. Cofree Collect/Disperse def collect[F[_]: MonadPlus, A](c: Cofree[F, A]): F[Vector[A]] = { val singleton = Vector[A](c.head).point[F] (singleton |@| c.tail.flatMap(collect(_)))(_ ++ _) <+> singleton } def disperse[F[_]: ApplicativePlus, A](seq: Seq[A]): Option[Cofree[F, A]] = seq.foldRight[Option[Cofree[F, A]]](None) { case (a, None) => Some(Cofree(a, mempty[F, Cofree[F, A]])) case (a, Some(tail)) => Some(Cofree(a, tail.point[F])) }
  23. 23. Cofree Zip def zipWith[F[_]: Zip: Functor, A, B, C]( c1: Cofree[F, A], c2: Cofree[F, B])( f: (A, B) => C): Cofree[F, C] = Cofree( f(c1.head, c2.head), Zip[F].zipWith(c1.tail, c2.tail)(zipWith(_, _)(f)))
  24. 24. Cofree Scan def scan[F[_]: Functor, A, S]( c: Cofree[F, A])(s: S)(f: (S, A) => S): Cofree[F, S] = { val s2 = f(s, c.head) Cofree(s2, c.tail.map(scan(_)(s2)(f))) }
  25. 25. Cofree Filter def zeros[F[_]: Functor, A: Monoid](c: Cofree[F, A])(p: A => Boolean): Cofree[F, A] = if (p(c.head)) Cofree(c.head, c.tail.map(zeros(_)(p))) else Cofree(mzero[A], c.tail.map(zeros(_)(p))) def filter[F[_]: Monad, A](c: Cofree[F, A])(p: A => Boolean): F[Cofree[F, A]] = if (p(c.head)) Cofree(c.head, c.tail.flatMap(filter(_)(p))).point[F] else c.tail.flatMap(filter(_)(p))
  26. 26. Cofree Pipes:Types // final case class Kleisli[F[_], A, B](run: A => F[B]) type Pipe[F[_], A, B] = Cofree[Kleisli[F, A, ?], B] type Source[F[_], A] = Pipe[F, Unit, A] type Sink[F[_], A] = Pipe[F, A, Unit]
  27. 27. Cofree Pipes: Utilities def pipe[F[_]: Applicative, A, B, C](from: Pipe[F, A, B], to: Pipe[F, B, C]): Pipe[F, A, C] = Cofree[Kleisli[F, A, ?], C]( to.head, Kleisli(a => (from.tail.run(a) |@| to.tail.run(from.head))(pipe(_, _)))) // e.g. Unit def runPipe[F[_]: Monad, A: Monoid](pipe: Pipe[F, A, A]): F[A] = (pipe.head.point[F] |@| pipe.tail.run(mzero[A]).flatMap(runPipe(_)))(_ |+| _)
  28. 28. Cofree IO, Byte Streams, Etc. type IOPipe[A, B] = Pipe[Task, A, B] ... type BytePipe = IOPipe[Array[Byte], Array[Byte]]
  29. 29. Cofree Merging:Types type Select[F[_], A] = Coproduct[F, F, A] type Merge[F[_], A, B] = Pipe[Select[F, ?], A, B]
  30. 30. Cofree Merging: Function def merge[F[_]: Applicative, A, B](left: Source[F, A], right: Source[F, A]) (s: Select[Id, Merge[F, A, B]]): Source[F, B] = { def embed[F[_]: Functor, A](s: Select[F, A]): F[Select[Id, A]] = s.run match { case -/ (fa) => fa.map(a => Coproduct[Id, Id, A](a.left [A])) case /-(fa) => fa.map(a => Coproduct[Id, Id, A](a.right[A])) } def step(y: Merge[F, A, B], fs: F[Source[F, B]]): Source[F, B] = Cofree[Kleisli[F, Unit, ?], B](y.head, Kleisli(_ => fs)) s.run match { case -/ (y) => step(y, (left.tail.run(()) |@| embed(y.tail.run(left.head)))( (left, y) => merge(left, right)(y))) case /-(y) => step(y, (right.tail.run(()) |@| embed(y.tail.run(right.head)))( (right, y) => merge(left, right)(y))) } }
  31. 31. Cofree Forking def fork[F[_]: Applicative, A](left: Sink[F, A], right: Sink[F, A]): Sink[F, A] = Cofree[Kleisli[F, A, ?], Unit]((), Kleisli(a => (left.tail.run(a) |@| right.tail.run(a))(fork(_, _))))
  32. 32. Cofree Machines case class Instr[F[_], A]( goLeft: F[A], goRight: F[A], goUp: F[A], goDown: F[A]) // Cofree[Instr[F, ?], A] def productWith[F[_]: Functor, G[_]: Functor, A, B, C]( c1: Cofree[F, A], c2: Cofree[G, B])( f: (A, B) => C): Cofree[Product[F, G, ?], C] = Cofree[Product[F, G, ?], C](f(c1.head, c2.head), Product((c1.tail.map(productWith(_, c2)(f)), c2.tail.map(productWith(c1, _)(f)))))
  33. 33. CofreeProduction-Ready? No, BUT...
  34. 34. ChallengeGo Do SomethingThat'sATinyBit Simpler...ABitMore Functional...
  35. 35. THANKYOUFollowme onTwitterat@jdegoes

×