This document discusses using Cofree to model streams and coinductive processes in a principled way. Cofree represents a current position that can move to new positions through effects. Various stream operations like append, collect, zip, and filter are implemented using the Cofree structure. Pipes and merging/forking of streams are also demonstrated using Cofree. The document concludes by challenging the reader to apply these ideas to build something simpler and more functional.
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
parametric 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]]