The Pierian Stream
Zainab Ali
Stream
Pierian
“A body of running water (such as a river or creek) flowing on earth.”
cat log.txt | uniq
java.io.FileOutputStream
Operators
repeat
infinity
evalMap
side effects
merge
concurrency
Composition
Stream("Mao", "Popcorn")
.evalMap(meow)
.repeat
.evalMap(eat)
And many more
fold
map
filter
collect
evalMap
evalScan
evalFilter
evalTap
merge
zip
append
flatMap
debounce
interruptAfter
groupWithin
delayBy
fs2 is awesome
...or is it?
The life of cats
def eat(cat: String): IO[String] =
IO.println(s"$cat eats.").as(cat)
def nap(cat: String): IO[Unit] =
IO.println(s"$cat naps.")
Stream("Mao", "Popcorn")
.evalMap(eat)
.evalMap(nap)
.repeat
Stream("Mao", "Popcorn")
.evalMap(eat)
.evalMap(nap)
.repeat
1
Mao naps.
Mao eats.
Popcorn naps.
Popcorn eats.
2
Mao eats.
Mao naps.
Popcorn eats.
Popcorn naps.
3
Mao eats.
Popcorn eats.
Mao naps.
Popcorn naps.
Does simple to read
mean simple to reason?
Pierian
“Of or relating to learning”.
Analogies
“A little learning is a dang'rous thing; Drink deep, or taste not the Pierian spring”
⸺ An Essay on Criticism, Alexander Pope
Analogies
Pros
- Physical
- Easy to start
Cons
- Fuzzy
- Misconceptions
Mental models
Experimentation
Stream("Mao", "Popcorn")
.evalMap(eat)
.evalMap(nap)
.repeat
Mao eats.
Mao naps.
Popcorn eats.
Popcorn naps.
Experimentation
Pros
- Independent
- Easy to do
Cons
- Need many
- Nondeterminism
Substitution
getOrElse(Some("Mao"), "Popcorn") === "Mao"
getOrElse(Some("Mao"), "Popcorn")
Some("Mao") match
case Some(name) => name
case None => "Popcorn"
case Some("Mao") => "Mao"
"Mao"
Stream("Mao", "Popcorn")
.evalMap(eat)
.evalMap(nap)
.repeat
Pull.output(Seq("Mao", "Popcorn")).streamNoScope.underlying
.evalMap(eat)
.evalMap(nap)
.repeat
Pull.output(Seq("Mao", "Popcorn"))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(eat(o)).flatMap(Pull.output1))
.streamNoScope.underlying
.evalMap(nap)
.repeat
Pull.output(Seq("Mao", "Popcorn"))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(eat(o)).flatMap(Pull.output1))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(nap(o)).flatMap(Pull.output1))
.streamNoScope.underlying
.repeat
Pull.output(Seq("Mao", "Popcorn"))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(eat(o)).flatMap(Pull.output1))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(nap(o)).flatMap(Pull.output1))
.streamNoScope.underlying ++
Pull.output(Seq("Mao", "Popcorn"))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(eat(o)).flatMap(Pull.output1))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(nap(o)).flatMap(Pull.output1))
.streamNoScope.underlying ++
Pull.output(Seq("Mao", "Popcorn"))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(eat(o)).flatMap(Pull.output1))
.streamNoScope.underlying
.flatMapOutput(o => Pull.eval(nap(o)).flatMap(Pull.output1))
.streamNoScope.underlying ++ ...
Mental stack overflow
Evaluation / substitution
Pros
- Set of steps
- Consistent
- Predictions
Cons
- Small functions
- Internal exposure
Equational reasoning
1
s.repeat === s ++ s ++ s ++ ...
2
(s1 ++ s2).evalMap(f) === s1.evalMap(f) ++ s2.evalMap(f)
Prove:
s.repeat.evalMap(eat) === s.evalMap(eat).repeat
mao.repeat.evalMap(eat) === mao.evalMap(eat).repeat
mao.repeat.evalMap(eat)
(mao ++ mao ++ ...).evalMap(eat) // law 1
(mao.evalMap(eat) ++ mao.evalMap(eat) + ...) // law 2
mao.evalMap(eat).repeat // law 1
A monad is just a monoid in the category of endofunctors, what's the problem?
Equational reasoning
Pros
- Consistent
- Predictions
- No internals
Cons
- Mathematical
- Hard to spot
Without a paddle
- Analogies
- Experiments
- Substitution & evaluation
- Equational reasoning
A better model
Physical analogy
Set of steps
Operators and composition
Predict behaviour
The pull model
We “pull” on a stream.
An operator:
- “pulls” on its upstream.
- Evaluates effects.
- Outputs its result.
- Or is “done”.
The pull model
Stream
evalMap
repeat
A better model
- A precise sequence of steps
- Describes composition
- Can use new operators
Limited
Pieria
- Streams
- Reasoning
- Analogies, experiments, mental models
- The pull model
Revolutionary
or is it?
More broadly
- Cats effect
- Optics
Thank you!
Questions
The Pierian Stream
By Zainab Ali
The Pierian Stream
- 867