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!
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
9. ByAnyOther Name
Astream isamainstream example ofacoinductive process.
» Data processing
» Web servers
» User-interfaces
» Discrete "FRP"
» So much more...
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.
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.
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. 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. Cofree
IO, Byte Streams, Etc.
type IOPipe[A, B] = Pipe[Task, A, B]
...
type BytePipe = IOPipe[Array[Byte], Array[Byte]]