Adam Rosien @arosien
Inner Product LLC inner-product.com
1 Apr 2019
Stream
?Read the Literature
Stream
is like a List
(where data is ordered by time, instead of space)
Stream
is like a List
Great artists steal
// Introduction forms
def fromIterator: Iterator[A] => Stream[A]
// Combinators
def map: Stream[A] => (A => B) => Stream[B]
// Elimination forms
def run: Stream[A] => (B, (B, A) => B) => B
plus laws
???
s?trait Stream[A] {
def map[B](f: A => B): Stream[B] = ???
def zip[B](that: Stream[B]): Stream[(A,B)] = ???
def flatMap[B](f: A => Stream[B]): Stream[B] = ???
def run[B](zero: B)(f: (B, A) => B): B = ???
}
object Stream {
def fromIterator[A](source: Iterator[A]): Stream[A] =
???
}
Reification
Reification
Reification
sealed trait Stream[A] {
import Stream._
def map[B](f: A => B): Stream[B] = Map(this, f)
def zip[B](that: Stream[B]): Stream[(A,B)] = Zip(this, that)
def flatMap[B](f: A => Stream[B]): Stream[B] = FlatMap(this, f)
def run[B](zero: B)(f: (B, A) => B): B = ???
}
object Stream {
final case class Map[A,B](source: Stream[A], f: A => B) extends Stream[B]
final case class Zip[A,B](left: Stream[A], right: Stream[B]) extends Stream[(A,B)]
final case class FlatMap[A,B](source: Stream[A], f: A => Stream[B]) extends Stream[B]
final case class FromIterator[A](source: Iterator[A]) extends Stream[A]
def fromIterator[A](source: Iterator[A]): Stream[A] =
FromIterator(source)
}
Reification
how do we run it?
Interpreter
Structural Recursion
Interpreter
Structural Recursion
Structural Recursion
how do we implement the ???
s?
def run[B](zero: B)(f: (B, A) => B): B = {
def loop[C](stream: Stream[C])(zero: B)(f: (B, C) => B): B =
stream match {
case Map(s, f2) => ???
case Zip(l, r) => ???
case FlatMap(s, f2) => ???
case FromIterator(s) => ???
}
loop(this)(zero)(f)
}
Follow the Types
Structural Recursion
Follow the Types
Follow the Types
def run[B](zero: B)(f: (B, A) => B): B = {
def loop[C](stream: Stream[C])(zero: B)(f: (B, C) => B): B =
stream match {
case Map(s, f2) => loop(s)(zero)((b, d) => f(b, f2(d)))
case Zip(l, r) => loop(l)(zero)((b, d) =>
loop(r)(zero)((b, e) => f(b, (d, e)))
)
case FlatMap(s, f2) => loop(s)(zero)((b, d) => loop(f2(d))(zero)(f))
case FromIterator(s) => s.foldLeft(zero)(f)
}
loop(this)(zero)(f)
}
operational
vs.
denotational
Read the Literature: great artists steal
Follow the Types: types before impl
Algebraic Data Types: ANDs and ORs
Structural Recursion: transform ADTs
Sequencing: what must happen after something else, and what things can happen at the same time.
Applicative
& Monad
Interpreters: separate what from how
Reification: functions as data
Church-Encoding: data as functions
Type Classes: ad-hoc polymorphism
Adam Rosien @arosien
Inner Product LLC inner-product.com
Hire us to teach your team! ☝︎
Special thanks to Noel Welsh for his hard work in codifying these strategies.