SlideShare a Scribd company logo
1 of 112
Download to read offline
Building

A

F

am
tre
lS
ona
cti
un

in Scala
Derek Wyatt
Twitter: @derekwyatt
Email: derek@derekwyatt.org
Structure
ctional Data
A Fun
Structure
ctional Data
A Fun
Streams are infinite and lazy
Structure
ctional Data
A Fun
Streams are infinite and lazy
They can be built using functions
Structure
ctional Data
A Fun
Streams are infinite and lazy
They can be built using functions
Designing one is fun and instructive
Structure
ctional Data
A Fun
Streams are infinite and lazy
They can be built using functions
Designing one is fun and instructive
❊

I am not an FP expert (but I do play one in presentations).
Much of what you see has been learned from Functional Programming in Scala
by Paul Chiusano and Rúnar Bjarnason
Strictness

L ziness
a
vs.
Strictness

L ziness
a
vs.

def strict(row: DBRow): Unit = {	
if (somecondition)	
// do something with row	
}
Strictness
fetchRow(42)

L ziness
a
vs.

def strict(row: DBRow): Unit = {	
if (somecondition)	
// do something with row	
}
Strictness
fetchRow(42)

L ziness
a
vs.

def strict(row: DBRow): Unit = {	
if (somecondition)	
// do something with row	
}
def lazy(row: => DBRow): Unit = {	
if (somecondition)	
// do something with row	
}
Strictness
fetchRow(42)

L ziness
a
vs.

se
fal
def strict(row: DBRow): Unit = {	
=
ion
if (somecondition)	
t
ndi
co
// do something with row	
me
so
}
def lazy(row: => DBRow): Unit = {	
if (somecondition)	
// do something with row	
}
Strictness
fetchRow(42)

evaluated

L ziness
a
vs.

se
Not Evaluated
fal
def strict(row: DBRow): Unit = {	
=
ion
if (somecondition)	
t
ndi
co
// do something with row	
me
so
}
def lazy(row: => DBRow): Unit = {	
if (somecondition)	
// do something with row	
}
List: A “Strict” Data Type
List: A “Strict” Data Type
(1 to 10).toList map { i =>
println(s”list -> map $i”)
i + 10
} filter { i =>
println(s”list -> filter $i”)
i % 2 == 0
}

[1, 2, ... 10]

toList
List: A “Strict” Data Type
(1 to 10).toList map { i =>
println(s”list -> map $i”)
i + 10
} filter { i =>
println(s”list -> filter $i”)
i % 2 == 0
}

[1, 2, ... 10]

Map [11, 12, ... 20]

toList

//
//
//
//
//

list
list
...	
list
list

-> map 1	
-> map 2	
-> map 9	
-> map 10
List: A “Strict” Data Type
(1 to 10).toList map { i =>
println(s”list -> map $i”)
i + 10
} filter { i =>
println(s”list -> filter $i”)
i % 2 == 0
}

[1, 2, ... 10]

Map [11, 12, ... 20]
Filter

toList

[12, 14, ... 20]

//
//
//
//
//
//
//
//
//
//

list
list
...	
list
list
list
list
...	
list
list

-> map 1	
-> map 2	
->
->
->
->

map 9	
map 10
10	
filter 11	
filter 12	

-> filter 19	
-> filter 20
ams: Lazy Ass Seqs
Stre
ams: Lazy Ass Seqs
Stre
Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}
ams: Lazy Ass Seqs
Stre
Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}

[1, ?]

Stream(1 to 10)
ams: Lazy Ass Seqs
Stre
Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}

[1, ?]
[11, ?]

Stream(1 to 10)
Map
ams: Lazy Ass Seqs
Stre
Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}

[1, ?]
[11, ?]

Stream(1 to 10)
Map

[12, ?]

Filter

The ?‘s are, essentially
functions
ams: Lazy Ass Seqs
Stre
Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}

[1, ?]
[11, ?]

Stream(1 to 10)
Map

[12, ?]

Filter

The ?‘s are, essentially
functions
ative purposes only
For il ustr
ams: Lazy Ass Seqs
Stre
Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}

[1, ?]
[11, ?]

Stream(1 to 10)
Map

[12, ?]

Filter

The ?‘s are, essentially
functions
ative purposes only
For il ustr

Stream transformation does not require traversal
ams: Lazy Ass Seqs
Stre
Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}

[1, ?]
[11, ?]

Stream(1 to 10)
Map

[12, ?]

Filter

The ?‘s are, essentially
functions
ative purposes only
For il ustr

Stream transformation does not require traversal
Transformations are applied on-demand as
traversal happens
Stream Definition
Stream Definition
trait Stream[+A] {
def uncons: Option[(A, Stream[A])]
}
Stream Definition
trait Stream[+A] {
def uncons: Option[(A, Stream[A])]
}

The “data” structure
Stream Definition
trait Stream[+A] {
def uncons: Option[(A, Stream[A])]
}

The “data” structure
Constructors

object Stream {
def empty[A]: Stream[A] = new Stream[A] {
def uncons = None
}
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = new Stream[A] {
def uncons = Some((hd, tl))
}
}
Stream Definition
trait Stream[+A] {
def uncons: Option[(A, Stream[A])]
}

The “data” structure
Constructors

object Stream {
def empty[A]: Stream[A] = new Stream[A] {
def uncons = None
}
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = new Stream[A] {
def uncons = Some((hd, tl))
}
}
Constructing Streams
Constructing Streams
val streamOfOne = cons(1, empty[Int])
val streamOfThree = cons(1, cons(2, cons(3, empty[Int])))
Constructing Streams
val streamOfOne = cons(1, empty[Int])
val streamOfThree = cons(1, cons(2, cons(3, empty[Int])))

Well, that

SUCKS...
Constructing Streams
val streamOfOne = cons(1, empty[Int])
val streamOfThree = cons(1, cons(2, cons(3, empty[Int])))

Well, that

SUCKS...

object Stream {
def apply[A](as: A*): Stream[A] = {

if (as.isEmpty) empty[A]
else cons(as.head, apply(as.tail:_*))
}
}
Constructing Streams
val streamOfOne = cons(1, empty[Int])
val streamOfThree = cons(1, cons(2, cons(3, empty[Int])))

Well, that

SUCKS...

val three = Stream(1, 2, 3)

object Stream {
def apply[A](as: A*): Stream[A] = {

if (as.isEmpty) empty[A]
else cons(as.head, apply(as.tail:_*))
}
}
The Stream... so far
The Stream... so far
trait Stream[+A] {
def uncons: Option[(A, Stream[A])]
}
!

object Stream {
def empty[A]: Stream[A] = new Stream[A] {
def uncons = None
}
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = new Stream[A] {
def uncons = Some((hd, tl))
}
def apply[A](as: A*): Stream[A] = {

if (as.isEmpty) empty[A]
else cons(as.head, apply(as.tail:_*))
}
}
Right (does it all)
fold
(1 to 4).foldRight(z)(f)
Right (does it all)
fold
(1 to 4).foldRight(z)(f)
makes

f(1, f(2, f(3, f(4, z))))
Right (does it all)
fold
(1 to 4).foldRight(z)(f)
makes

or

f(1, f(2, f(3, f(4, z))))
f(1,
f(1,
f(1,
f(1,
f(1,
f(1,
f(1,
res4

...
f(2, ...
f(2, f(3, ...
f(2, f(3, f(4, z))))
f(2, f(3, res1)))
f(2, res2))
res3)
Right (does it all)
fold
(1 to 4).foldRight(z)(f)
Builds a functional
structure “to the right”,
pushing successive
evaluation to the
second parameter.

makes

or

Each function’s second
parameter must be evaluated
before its predecessor can be
evaluated.

f(1, f(2, f(3, f(4, z))))
f(1,
f(1,
f(1,
f(1,
f(1,
f(1,
f(1,
res4

...
f(2, ...
f(2, f(3, ...
f(2, f(3, f(4, z))))
f(2, f(3, res1)))
f(2, res2))
res3)
foldRight for Lists
foldRight for Lists
case class List[+A](head: A, tail: List[A]) {
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
else f(head, tail.foldRight(z)(f))
}
foldRight for Lists
case class List[+A](head: A, tail: List[A]) {
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
else f(head, tail.foldRight(z)(f))
}
val sum
// f(1,
// f(1,
// f(1,
// f(1,
// f(1,
// f(1,
// f(1,
// 10

= (1 to 4).foldRight(0)(_ + _)
tail.foldRight...
f(2, tail.foldRight...
f(2, f(3, tail.foldRight...
f(2, f(3, f(4, 0))))
f(2, f(3, 4)))
f(2, 7))
9)
foldRight for Lists
case class List[+A](head: A, tail: List[A]) {
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
else f(head, tail.foldRight(z)(f))
}

Here A and B are both
Ints but they need not
be. Note that full
recursive expansion takes
place at the call site.

val sum
// f(1,
// f(1,
// f(1,
// f(1,
// f(1,
// f(1,
// f(1,
// 10

= (1 to 4).foldRight(0)(_ + _)
tail.foldRight...
f(2, tail.foldRight...
f(2, f(3, tail.foldRight...
f(2, f(3, f(4, 0))))
f(2, f(3, 4)))
f(2, 7))
9)
Strictly Folding Right
Strictly Folding Right
No application of ‘f’ can complete until all of its parameters
℥
have been applied
Strictly Folding Right
No application of ‘f’ can complete until all of its parameters
℥
have been applied
Strictly speaking, this means that foldRight must fully
℥
expand into a deeply nested function application
Strictly Folding Right
No application of ‘f’ can complete until all of its parameters
℥
have been applied
Strictly speaking, this means that foldRight must fully
℥
expand into a deeply nested function application
If the collection is infinite, or even significantly large, your
℥
application is doomed
Strictly Folding Right
No application of ‘f’ can complete until all of its parameters
℥
have been applied
Strictly speaking, this means that foldRight must fully
℥
expand into a deeply nested function application
If the collection is infinite, or even significantly large, your
℥
application is doomed
Building foldRight
Building foldRight
trait Stream[+A] {
def foldRight[B](z: ? B)(f: (A, ? B) => B): B
}
Building foldRight
trait Stream[+A]Stream[+A] {
trait {
def uncons: Option[(A, Stream[A])]
def foldRight[B](z: ? B)(f: (A, ? B) => B): B
!
}
def foldRight[B](z: => B)(f: (A, => B) => B): B = uncons match {
case None => z
case Some((hd, tl)) => f(hd, tl.foldRight(z)(f))
}
}
Building foldRight
trait Stream[+A]Stream[+A] {
trait {
def uncons: Option[(A, Stream[A])]
def foldRight[B](z: ? B)(f: (A, ? B) => B): B
!
}
def foldRight[B](z: => B)(f: (A, => B) => B): B = uncons match {
case None => z
case Some((hd, tl)) => f(hd, tl.foldRight(z)(f))
}
}

A profound change!
Building foldRight
trait Stream[+A]Stream[+A] {
trait {
def uncons: Option[(A, Stream[A])]
def foldRight[B](z: ? B)(f: (A, ? B) => B): B
!
}
def foldRight[B](z: => B)(f: (A, => B) => B): B = uncons match {
case None => z
case Some((hd, tl)) => f(hd, tl.foldRight(z)(f))
}
}

The recursive call is no longer evaluated at the call site
because ‘f’ receives it by name
Learning to Relax
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B

At this point, you’re potentially confused
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B

At this point, you’re potentially confused
What good is it to have a lazy => B when foldRight must return a strict B?
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B

At this point, you’re potentially confused
What good is it to have a lazy => B when foldRight must return a strict B?
def sum(ints: Stream[Int]): Int = ints.foldRight(0)(_ + _)
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B

At this point, you’re potentially confused
What good is it to have a lazy => B when foldRight must return a strict B?
def sum(ints: Stream[Int]): Int = ints.foldRight(0)(_ + _)

val neverGetsHere = sum(streamOfNaturalNumbers)
Learning to Relax

!
e
yp

def foldRight[B](z: => B)(f: (A, => B) => B): B

T
”
T

IC
TR
S

At this point, you’re potentially confused

“
a
s

What good is it to have a lazy => B when foldRight must return a strict B?

I

i
t
n

def sum(ints: Stream[Int]): Int = ints.foldRight(0)(_ + _)

val neverGetsHere = sum(streamOfNaturalNumbers)
Learning to Relax
Learning to Relax
Ok, I kinda lied… it’s not that Int is a “strict type”
(You can, of course, do something useful with an Int… such as)
Learning to Relax
Ok, I kinda lied… it’s not that Int is a “strict type”
(You can, of course, do something useful with an Int… such as)
def sumToN(ints: Stream[Int], to: Int): Int =
ints.take(to).foldRight(0)(_ + _)
Learning to Relax
Ok, I kinda lied… it’s not that Int is a “strict type”
(You can, of course, do something useful with an Int… such as)
def sumToN(ints: Stream[Int], to: Int): Int =
ints.take(to).foldRight(0)(_ + _)

It’s just that the strict type can cause a bit of confusion because of its
non-lazy nature.
Learning to Relax
Ok, I kinda lied… it’s not that Int is a “strict type”
(You can, of course, do something useful with an Int… such as)
def sumToN(ints: Stream[Int], to: Int): Int =
ints.take(to).foldRight(0)(_ + _)

It’s just that the strict type can cause a bit of confusion because of its
non-lazy nature.
The more “interesting” stuff, though happens when you can continue
beings lazy and stay within the realm of the infinite
Learning to Relax
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B

Switching to a lazy (by name) parameter gives ‘f’ control
over the recursion
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B

Switching to a lazy (by name) parameter gives ‘f’ control
over the recursion
‘f’ can decide to delay the execution of its second parameter,
eliminating the recursive call, returning control to the caller
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B

Switching to a lazy (by name) parameter gives ‘f’ control
over the recursion
‘f’ can decide to delay the execution of its second parameter,
eliminating the recursive call, returning control to the caller
However, you can’t just delay a computation without shoving
it into some sort of context...
Learning to Relax

M
A
E
R
T
t!
S
x
e
e
t
h
n
T
o
c
t
a
th
is
def foldRight[B](z: => B)(f: (A, => B) => B): B

Switching to a lazy (by name) parameter gives ‘f’ control
over the recursion
‘f’ can decide to delay the execution of its second parameter,
eliminating the recursive call, returning control to the caller
However, you can’t just delay a computation without shoving
it into some sort of context...
A Match Made in Laziness

=>

+

Non-Strict
Result

=

Lazy
Stream
Enter... Map
Enter... Map
def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>
cons(f(head), tail)
}
Enter... Map
def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>
cons(f(head), tail)
}

def foldRight[B](z: => B)(f: (A, => B) => B): B
Enter... Map
St
r

ea

def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>
cons(f(head), tail)
}

Stream!

St
r

ea

m

St
r

!

ea

m

m

!

!

def foldRight[B](z: => B)(f: (A, => B) => B): B
Enter... Filter
Enter... Filter
def filter(p: A => Boolean): Stream[A] =
foldRight(empty[A]) { (head, tail) =>
if (p(head)) cons(head, tail)
else tail
}
Enter... Filter
def filter(p: A => Boolean): Stream[A] =
foldRight(empty[A]) { (head, tail) =>
if (p(head)) cons(head, tail)
else tail
}

def foldRight[B](z: => B)(f: (A, => B) => B): B
Enter... Filter
def filter(p: A => Boolean): Stream[A] =
foldRight(empty[A]) { (head, tail) =>
if (p(head)) cons(head, tail)
else tail
St
re
}

am

Stream!

!

St
r

ea

St
r

ea

m

m

!

def foldRight[B](z: => B)(f: (A, => B) => B): B

!
Returning Streams
Returning Streams
Both map and filter return Streams
Returning Streams
Both map and filter return Streams
Stream’s constructors eval neither head nor tail
Returning Streams
Both map and filter return Streams
Stream’s constructors eval neither head nor tail
This allows for the chaining of laziness from the
by name parameter of foldRight, into the return value
Returning Streams
Returning Streams
def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>
Returning Streams
def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>

Not Eval’d
Returning Streams
def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>
!
!
!

Not Eval’d

!

Not Eval’d

!

cons(f(head), tail)
}
Returning Streams
def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>
!
!
!

Not Eval’d

Not Eval’d

!

Not Eval’d

!

cons(f(head), tail)
}
Returning Streams
def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>
!
!
!

Not Eval’d

Not Eval’d

!

Not Eval’d

!

cons(f(head), tail)
}

Jeez, does
this code
even do
anything!?
Let’s find Out...
Let’s find Out...
Stream(1, 2, 3, 4, 5) map { i =>
println(s"map -> $i")
i * i
}
Let’s find Out...
Stream(1, 2, 3, 4, 5) map { i =>
println(s"map -> $i")
i * i
}

Which prints...

def map[T](f: A => T): Stream[T] =
foldRight(empty[T]) { (head, tail) =>
cons(f(head), tail)
}

Remember
that...
and...

def foldRight[B](z: => B)(f: (A, => B) => B): B
def cons[A](hd: => A, tl: => Stream[A]): Stream[A]

and...
This page intentionally left blank
Putting it All Together
Putting it All Together
val s = Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}
Putting it All Together
val s = Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}

Prints nothing.
OK
Putting it All Together
val s = Stream(1 to 10) map { i =>
println(s”stream -> map $i”)
i + 10
} filter { i =>
println(s”stream -> filter $i”)
i % 2 == 0
}

def toList: List[A] = uncons match {
case None => Nil
case Some((h, t)) => h :: t.toList
}

Prints nothing.
OK

add toList()
Evaluating
Evaluating
val numList = s.toList
Evaluating
val numList = s.toList

//
//
//
//
//
//
//

stream
stream
stream
stream
...	
stream
stream

->
->
->
->

map 1	
filter 11	
map 2	
filter 12	

-> map 10	
-> filter 20
Evaluating
val numList = s.toList

def take(n: Int): Stream[A] =
uncons match {
case Some((h, t)) if n > 0 =>
cons(h, t.take(n - 1))
case _ =>
empty
}

//
//
//
//
//
//
//

stream
stream
stream
stream
...	
stream
stream

->
->
->
->

map 1	
filter 11	
map 2	
filter 12	

-> map 10	
-> filter 20
Evaluating
val numList = s.toList

def take(n: Int): Stream[A] =
uncons match {
case Some((h, t)) if n > 0 =>
cons(h, t.take(n - 1))
case _ =>
empty
}

val numList = s.take(1).toList

//
//
//
//
//
//
//

stream
stream
stream
stream
...	
stream
stream

->
->
->
->

map 1	
filter 11	
map 2	
filter 12	

-> map 10	
-> filter 20
Evaluating
val numList = s.toList

def take(n: Int): Stream[A] =
uncons match {
case Some((h, t)) if n > 0 =>
cons(h, t.take(n - 1))
case _ =>
empty
}

val numList = s.take(1).toList

//
//
//
//
//
//
//

stream
stream
stream
stream
...	
stream
stream

//
//
//
//

->
->
->
->

map 1	
filter 11	
map 2	
filter 12	

-> map 10	
-> filter 20

stream
stream
stream
stream

->
->
->
->

map 1	
filter 11	
map 2	
filter 12
It’s All About Functions
It’s All About Functions
Functions hold the values
It’s All About Functions
Functions hold the values
Higher order functions pile functions on functions
It’s All About Functions
Functions hold the values
Higher order functions pile functions on functions
Even functions like take() merely store functions
It’s All About Functions
Functions hold the values
Higher order functions pile functions on functions
Even functions like take() merely store functions
Nothing “real” happens until you need it to happen
It’s All About Functions
Functions hold the values
Higher order functions pile functions on functions
Even functions like take() merely store functions
Nothing “real” happens until you need it to happen

!
y
in
h
S
ms
rea
St
ss
yA
az

L

i

Brought to you
Sincere Couch Potato
em
s

Derek Wyatt
Twitter: @derekwyatt
Email: derek@derekwyatt.org

More Related Content

What's hot

Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free MonadsJohn De Goes
 
Compositional I/O Stream in Scala
Compositional I/O Stream in ScalaCompositional I/O Stream in Scala
Compositional I/O Stream in ScalaC4Media
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
 
Sequence and Traverse - Part 1
Sequence and Traverse - Part 1Sequence and Traverse - Part 1
Sequence and Traverse - Part 1Philip Schwarz
 
ZIO Schedule: Conquering Flakiness & Recurrence with Pure Functional Programming
ZIO Schedule: Conquering Flakiness & Recurrence with Pure Functional ProgrammingZIO Schedule: Conquering Flakiness & Recurrence with Pure Functional Programming
ZIO Schedule: Conquering Flakiness & Recurrence with Pure Functional ProgrammingJohn De Goes
 
Scalaエンジニアのためのモナド入門
Scalaエンジニアのためのモナド入門Scalaエンジニアのためのモナド入門
Scalaエンジニアのためのモナド入門Takashi Imahiro
 
Munihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template HaskellMunihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template HaskellMatthew Pickering
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1Hang Zhao
 
A Survey Of R Graphics
A Survey Of R GraphicsA Survey Of R Graphics
A Survey Of R GraphicsDataspora
 
Functional programming in Swift
Functional programming in SwiftFunctional programming in Swift
Functional programming in SwiftJohn Pham
 
FS2 for Fun and Profit
FS2 for Fun and ProfitFS2 for Fun and Profit
FS2 for Fun and ProfitAdil Akhter
 
Why functional why scala
Why functional  why scala Why functional  why scala
Why functional why scala Neville Li
 
Introducing Monads and State Monad at PSUG
Introducing Monads and State Monad at PSUGIntroducing Monads and State Monad at PSUG
Introducing Monads and State Monad at PSUGDavid Galichet
 
The Gremlin Graph Traversal Language
The Gremlin Graph Traversal LanguageThe Gremlin Graph Traversal Language
The Gremlin Graph Traversal LanguageMarko Rodriguez
 
Rewriting Java In Scala
Rewriting Java In ScalaRewriting Java In Scala
Rewriting Java In ScalaSkills Matter
 
Collections In Scala
Collections In ScalaCollections In Scala
Collections In ScalaKnoldus Inc.
 

What's hot (20)

Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
 
Compositional I/O Stream in Scala
Compositional I/O Stream in ScalaCompositional I/O Stream in Scala
Compositional I/O Stream in Scala
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 
Sequence and Traverse - Part 1
Sequence and Traverse - Part 1Sequence and Traverse - Part 1
Sequence and Traverse - Part 1
 
ZIO Schedule: Conquering Flakiness & Recurrence with Pure Functional Programming
ZIO Schedule: Conquering Flakiness & Recurrence with Pure Functional ProgrammingZIO Schedule: Conquering Flakiness & Recurrence with Pure Functional Programming
ZIO Schedule: Conquering Flakiness & Recurrence with Pure Functional Programming
 
Scalaエンジニアのためのモナド入門
Scalaエンジニアのためのモナド入門Scalaエンジニアのためのモナド入門
Scalaエンジニアのためのモナド入門
 
Fs2 - Crash Course
Fs2 - Crash CourseFs2 - Crash Course
Fs2 - Crash Course
 
Munihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template HaskellMunihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template Haskell
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1
 
A Survey Of R Graphics
A Survey Of R GraphicsA Survey Of R Graphics
A Survey Of R Graphics
 
Functional programming in Swift
Functional programming in SwiftFunctional programming in Swift
Functional programming in Swift
 
FS2 for Fun and Profit
FS2 for Fun and ProfitFS2 for Fun and Profit
FS2 for Fun and Profit
 
N flavors of streaming
N flavors of streamingN flavors of streaming
N flavors of streaming
 
Why functional why scala
Why functional  why scala Why functional  why scala
Why functional why scala
 
Introducing Monads and State Monad at PSUG
Introducing Monads and State Monad at PSUGIntroducing Monads and State Monad at PSUG
Introducing Monads and State Monad at PSUG
 
The Gremlin Graph Traversal Language
The Gremlin Graph Traversal LanguageThe Gremlin Graph Traversal Language
The Gremlin Graph Traversal Language
 
Scala collections
Scala collectionsScala collections
Scala collections
 
Rewriting Java In Scala
Rewriting Java In ScalaRewriting Java In Scala
Rewriting Java In Scala
 
Fun with Kotlin
Fun with KotlinFun with Kotlin
Fun with Kotlin
 
Collections In Scala
Collections In ScalaCollections In Scala
Collections In Scala
 

Viewers also liked

The Lies We Tell Our Code (#seascale 2015 04-22)
The Lies We Tell Our Code (#seascale 2015 04-22)The Lies We Tell Our Code (#seascale 2015 04-22)
The Lies We Tell Our Code (#seascale 2015 04-22)Casey Bisson
 
Introduction to Microsoft Azure
Introduction to Microsoft AzureIntroduction to Microsoft Azure
Introduction to Microsoft AzureMartyn Coupland
 
Playing with State Monad
Playing with State MonadPlaying with State Monad
Playing with State MonadDavid Galichet
 
How to Become a Thought Leader in Your Niche
How to Become a Thought Leader in Your NicheHow to Become a Thought Leader in Your Niche
How to Become a Thought Leader in Your NicheLeslie Samuel
 

Viewers also liked (6)

The Lies We Tell Our Code (#seascale 2015 04-22)
The Lies We Tell Our Code (#seascale 2015 04-22)The Lies We Tell Our Code (#seascale 2015 04-22)
The Lies We Tell Our Code (#seascale 2015 04-22)
 
Introduction to Microsoft Azure
Introduction to Microsoft AzureIntroduction to Microsoft Azure
Introduction to Microsoft Azure
 
WikiLeaks
WikiLeaksWikiLeaks
WikiLeaks
 
Playing with State Monad
Playing with State MonadPlaying with State Monad
Playing with State Monad
 
Build Features, Not Apps
Build Features, Not AppsBuild Features, Not Apps
Build Features, Not Apps
 
How to Become a Thought Leader in Your Niche
How to Become a Thought Leader in Your NicheHow to Become a Thought Leader in Your Niche
How to Become a Thought Leader in Your Niche
 

Similar to Building a Functional Stream in Scala

Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2Hang Zhao
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final TaglessJohn De Goes
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsJohn De Goes
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2Hang Zhao
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator PatternEric Torreborre
 
Monadologie
MonadologieMonadologie
Monadologieleague
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009David Pollak
 
The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)Eric Torreborre
 
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Ruslan Shevchenko
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Jonas Bonér
 
Pragmatic Real-World Scala
Pragmatic Real-World ScalaPragmatic Real-World Scala
Pragmatic Real-World Scalaparag978978
 
Scala Collections : Java 8 on Steroids
Scala Collections : Java 8 on SteroidsScala Collections : Java 8 on Steroids
Scala Collections : Java 8 on SteroidsFrançois Garillot
 
Free Based DSLs for Distributed Compute Engines
Free Based DSLs for Distributed Compute EnginesFree Based DSLs for Distributed Compute Engines
Free Based DSLs for Distributed Compute EnginesJoydeep Banik Roy
 

Similar to Building a Functional Stream in Scala (20)

Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Monadologie
MonadologieMonadologie
Monadologie
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009
 
The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)
 
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)
 
Pragmatic Real-World Scala
Pragmatic Real-World ScalaPragmatic Real-World Scala
Pragmatic Real-World Scala
 
Scala Collections : Java 8 on Steroids
Scala Collections : Java 8 on SteroidsScala Collections : Java 8 on Steroids
Scala Collections : Java 8 on Steroids
 
Free Based DSLs for Distributed Compute Engines
Free Based DSLs for Distributed Compute EnginesFree Based DSLs for Distributed Compute Engines
Free Based DSLs for Distributed Compute Engines
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 

Recently uploaded

Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 

Recently uploaded (20)

Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 

Building a Functional Stream in Scala

  • 1. Building A F am tre lS ona cti un in Scala Derek Wyatt Twitter: @derekwyatt Email: derek@derekwyatt.org
  • 3. Structure ctional Data A Fun Streams are infinite and lazy
  • 4. Structure ctional Data A Fun Streams are infinite and lazy They can be built using functions
  • 5. Structure ctional Data A Fun Streams are infinite and lazy They can be built using functions Designing one is fun and instructive
  • 6. Structure ctional Data A Fun Streams are infinite and lazy They can be built using functions Designing one is fun and instructive ❊ I am not an FP expert (but I do play one in presentations). Much of what you see has been learned from Functional Programming in Scala by Paul Chiusano and Rúnar Bjarnason
  • 8. Strictness L ziness a vs. def strict(row: DBRow): Unit = { if (somecondition) // do something with row }
  • 9. Strictness fetchRow(42) L ziness a vs. def strict(row: DBRow): Unit = { if (somecondition) // do something with row }
  • 10. Strictness fetchRow(42) L ziness a vs. def strict(row: DBRow): Unit = { if (somecondition) // do something with row } def lazy(row: => DBRow): Unit = { if (somecondition) // do something with row }
  • 11. Strictness fetchRow(42) L ziness a vs. se fal def strict(row: DBRow): Unit = { = ion if (somecondition) t ndi co // do something with row me so } def lazy(row: => DBRow): Unit = { if (somecondition) // do something with row }
  • 12. Strictness fetchRow(42) evaluated L ziness a vs. se Not Evaluated fal def strict(row: DBRow): Unit = { = ion if (somecondition) t ndi co // do something with row me so } def lazy(row: => DBRow): Unit = { if (somecondition) // do something with row }
  • 13. List: A “Strict” Data Type
  • 14. List: A “Strict” Data Type (1 to 10).toList map { i => println(s”list -> map $i”) i + 10 } filter { i => println(s”list -> filter $i”) i % 2 == 0 } [1, 2, ... 10] toList
  • 15. List: A “Strict” Data Type (1 to 10).toList map { i => println(s”list -> map $i”) i + 10 } filter { i => println(s”list -> filter $i”) i % 2 == 0 } [1, 2, ... 10] Map [11, 12, ... 20] toList // // // // // list list ... list list -> map 1 -> map 2 -> map 9 -> map 10
  • 16. List: A “Strict” Data Type (1 to 10).toList map { i => println(s”list -> map $i”) i + 10 } filter { i => println(s”list -> filter $i”) i % 2 == 0 } [1, 2, ... 10] Map [11, 12, ... 20] Filter toList [12, 14, ... 20] // // // // // // // // // // list list ... list list list list ... list list -> map 1 -> map 2 -> -> -> -> map 9 map 10 10 filter 11 filter 12 -> filter 19 -> filter 20
  • 17. ams: Lazy Ass Seqs Stre
  • 18. ams: Lazy Ass Seqs Stre Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 }
  • 19. ams: Lazy Ass Seqs Stre Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 } [1, ?] Stream(1 to 10)
  • 20. ams: Lazy Ass Seqs Stre Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 } [1, ?] [11, ?] Stream(1 to 10) Map
  • 21. ams: Lazy Ass Seqs Stre Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 } [1, ?] [11, ?] Stream(1 to 10) Map [12, ?] Filter The ?‘s are, essentially functions
  • 22. ams: Lazy Ass Seqs Stre Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 } [1, ?] [11, ?] Stream(1 to 10) Map [12, ?] Filter The ?‘s are, essentially functions ative purposes only For il ustr
  • 23. ams: Lazy Ass Seqs Stre Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 } [1, ?] [11, ?] Stream(1 to 10) Map [12, ?] Filter The ?‘s are, essentially functions ative purposes only For il ustr Stream transformation does not require traversal
  • 24. ams: Lazy Ass Seqs Stre Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 } [1, ?] [11, ?] Stream(1 to 10) Map [12, ?] Filter The ?‘s are, essentially functions ative purposes only For il ustr Stream transformation does not require traversal Transformations are applied on-demand as traversal happens
  • 26. Stream Definition trait Stream[+A] { def uncons: Option[(A, Stream[A])] }
  • 27. Stream Definition trait Stream[+A] { def uncons: Option[(A, Stream[A])] } The “data” structure
  • 28. Stream Definition trait Stream[+A] { def uncons: Option[(A, Stream[A])] } The “data” structure Constructors object Stream { def empty[A]: Stream[A] = new Stream[A] { def uncons = None } def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = new Stream[A] { def uncons = Some((hd, tl)) } }
  • 29. Stream Definition trait Stream[+A] { def uncons: Option[(A, Stream[A])] } The “data” structure Constructors object Stream { def empty[A]: Stream[A] = new Stream[A] { def uncons = None } def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = new Stream[A] { def uncons = Some((hd, tl)) } }
  • 31. Constructing Streams val streamOfOne = cons(1, empty[Int]) val streamOfThree = cons(1, cons(2, cons(3, empty[Int])))
  • 32. Constructing Streams val streamOfOne = cons(1, empty[Int]) val streamOfThree = cons(1, cons(2, cons(3, empty[Int]))) Well, that SUCKS...
  • 33. Constructing Streams val streamOfOne = cons(1, empty[Int]) val streamOfThree = cons(1, cons(2, cons(3, empty[Int]))) Well, that SUCKS... object Stream { def apply[A](as: A*): Stream[A] = {
 if (as.isEmpty) empty[A] else cons(as.head, apply(as.tail:_*)) } }
  • 34. Constructing Streams val streamOfOne = cons(1, empty[Int]) val streamOfThree = cons(1, cons(2, cons(3, empty[Int]))) Well, that SUCKS... val three = Stream(1, 2, 3) object Stream { def apply[A](as: A*): Stream[A] = {
 if (as.isEmpty) empty[A] else cons(as.head, apply(as.tail:_*)) } }
  • 36. The Stream... so far trait Stream[+A] { def uncons: Option[(A, Stream[A])] } ! object Stream { def empty[A]: Stream[A] = new Stream[A] { def uncons = None } def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = new Stream[A] { def uncons = Some((hd, tl)) } def apply[A](as: A*): Stream[A] = {
 if (as.isEmpty) empty[A] else cons(as.head, apply(as.tail:_*)) } }
  • 37. Right (does it all) fold (1 to 4).foldRight(z)(f)
  • 38. Right (does it all) fold (1 to 4).foldRight(z)(f) makes f(1, f(2, f(3, f(4, z))))
  • 39. Right (does it all) fold (1 to 4).foldRight(z)(f) makes or f(1, f(2, f(3, f(4, z)))) f(1, f(1, f(1, f(1, f(1, f(1, f(1, res4 ... f(2, ... f(2, f(3, ... f(2, f(3, f(4, z)))) f(2, f(3, res1))) f(2, res2)) res3)
  • 40. Right (does it all) fold (1 to 4).foldRight(z)(f) Builds a functional structure “to the right”, pushing successive evaluation to the second parameter. makes or Each function’s second parameter must be evaluated before its predecessor can be evaluated. f(1, f(2, f(3, f(4, z)))) f(1, f(1, f(1, f(1, f(1, f(1, f(1, res4 ... f(2, ... f(2, f(3, ... f(2, f(3, f(4, z)))) f(2, f(3, res1))) f(2, res2)) res3)
  • 42. foldRight for Lists case class List[+A](head: A, tail: List[A]) { def foldRight[B](z: B)(f: (A, B) => B): B = if (this.isEmpty) z else f(head, tail.foldRight(z)(f)) }
  • 43. foldRight for Lists case class List[+A](head: A, tail: List[A]) { def foldRight[B](z: B)(f: (A, B) => B): B = if (this.isEmpty) z else f(head, tail.foldRight(z)(f)) } val sum // f(1, // f(1, // f(1, // f(1, // f(1, // f(1, // f(1, // 10 = (1 to 4).foldRight(0)(_ + _) tail.foldRight... f(2, tail.foldRight... f(2, f(3, tail.foldRight... f(2, f(3, f(4, 0)))) f(2, f(3, 4))) f(2, 7)) 9)
  • 44. foldRight for Lists case class List[+A](head: A, tail: List[A]) { def foldRight[B](z: B)(f: (A, B) => B): B = if (this.isEmpty) z else f(head, tail.foldRight(z)(f)) } Here A and B are both Ints but they need not be. Note that full recursive expansion takes place at the call site. val sum // f(1, // f(1, // f(1, // f(1, // f(1, // f(1, // f(1, // 10 = (1 to 4).foldRight(0)(_ + _) tail.foldRight... f(2, tail.foldRight... f(2, f(3, tail.foldRight... f(2, f(3, f(4, 0)))) f(2, f(3, 4))) f(2, 7)) 9)
  • 46. Strictly Folding Right No application of ‘f’ can complete until all of its parameters ℥ have been applied
  • 47. Strictly Folding Right No application of ‘f’ can complete until all of its parameters ℥ have been applied Strictly speaking, this means that foldRight must fully ℥ expand into a deeply nested function application
  • 48. Strictly Folding Right No application of ‘f’ can complete until all of its parameters ℥ have been applied Strictly speaking, this means that foldRight must fully ℥ expand into a deeply nested function application If the collection is infinite, or even significantly large, your ℥ application is doomed
  • 49. Strictly Folding Right No application of ‘f’ can complete until all of its parameters ℥ have been applied Strictly speaking, this means that foldRight must fully ℥ expand into a deeply nested function application If the collection is infinite, or even significantly large, your ℥ application is doomed
  • 51. Building foldRight trait Stream[+A] { def foldRight[B](z: ? B)(f: (A, ? B) => B): B }
  • 52. Building foldRight trait Stream[+A]Stream[+A] { trait { def uncons: Option[(A, Stream[A])] def foldRight[B](z: ? B)(f: (A, ? B) => B): B ! } def foldRight[B](z: => B)(f: (A, => B) => B): B = uncons match { case None => z case Some((hd, tl)) => f(hd, tl.foldRight(z)(f)) } }
  • 53. Building foldRight trait Stream[+A]Stream[+A] { trait { def uncons: Option[(A, Stream[A])] def foldRight[B](z: ? B)(f: (A, ? B) => B): B ! } def foldRight[B](z: => B)(f: (A, => B) => B): B = uncons match { case None => z case Some((hd, tl)) => f(hd, tl.foldRight(z)(f)) } } A profound change!
  • 54. Building foldRight trait Stream[+A]Stream[+A] { trait { def uncons: Option[(A, Stream[A])] def foldRight[B](z: ? B)(f: (A, ? B) => B): B ! } def foldRight[B](z: => B)(f: (A, => B) => B): B = uncons match { case None => z case Some((hd, tl)) => f(hd, tl.foldRight(z)(f)) } } The recursive call is no longer evaluated at the call site because ‘f’ receives it by name
  • 56. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B
  • 57. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B At this point, you’re potentially confused
  • 58. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B At this point, you’re potentially confused What good is it to have a lazy => B when foldRight must return a strict B?
  • 59. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B At this point, you’re potentially confused What good is it to have a lazy => B when foldRight must return a strict B? def sum(ints: Stream[Int]): Int = ints.foldRight(0)(_ + _)
  • 60. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B At this point, you’re potentially confused What good is it to have a lazy => B when foldRight must return a strict B? def sum(ints: Stream[Int]): Int = ints.foldRight(0)(_ + _) val neverGetsHere = sum(streamOfNaturalNumbers)
  • 61. Learning to Relax ! e yp def foldRight[B](z: => B)(f: (A, => B) => B): B T ” T IC TR S At this point, you’re potentially confused “ a s What good is it to have a lazy => B when foldRight must return a strict B? I i t n def sum(ints: Stream[Int]): Int = ints.foldRight(0)(_ + _) val neverGetsHere = sum(streamOfNaturalNumbers)
  • 63. Learning to Relax Ok, I kinda lied… it’s not that Int is a “strict type” (You can, of course, do something useful with an Int… such as)
  • 64. Learning to Relax Ok, I kinda lied… it’s not that Int is a “strict type” (You can, of course, do something useful with an Int… such as) def sumToN(ints: Stream[Int], to: Int): Int = ints.take(to).foldRight(0)(_ + _)
  • 65. Learning to Relax Ok, I kinda lied… it’s not that Int is a “strict type” (You can, of course, do something useful with an Int… such as) def sumToN(ints: Stream[Int], to: Int): Int = ints.take(to).foldRight(0)(_ + _) It’s just that the strict type can cause a bit of confusion because of its non-lazy nature.
  • 66. Learning to Relax Ok, I kinda lied… it’s not that Int is a “strict type” (You can, of course, do something useful with an Int… such as) def sumToN(ints: Stream[Int], to: Int): Int = ints.take(to).foldRight(0)(_ + _) It’s just that the strict type can cause a bit of confusion because of its non-lazy nature. The more “interesting” stuff, though happens when you can continue beings lazy and stay within the realm of the infinite
  • 68. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B
  • 69. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B Switching to a lazy (by name) parameter gives ‘f’ control over the recursion
  • 70. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B Switching to a lazy (by name) parameter gives ‘f’ control over the recursion ‘f’ can decide to delay the execution of its second parameter, eliminating the recursive call, returning control to the caller
  • 71. Learning to Relax def foldRight[B](z: => B)(f: (A, => B) => B): B Switching to a lazy (by name) parameter gives ‘f’ control over the recursion ‘f’ can decide to delay the execution of its second parameter, eliminating the recursive call, returning control to the caller However, you can’t just delay a computation without shoving it into some sort of context...
  • 72. Learning to Relax M A E R T t! S x e e t h n T o c t a th is def foldRight[B](z: => B)(f: (A, => B) => B): B Switching to a lazy (by name) parameter gives ‘f’ control over the recursion ‘f’ can decide to delay the execution of its second parameter, eliminating the recursive call, returning control to the caller However, you can’t just delay a computation without shoving it into some sort of context...
  • 73. A Match Made in Laziness => + Non-Strict Result = Lazy Stream
  • 75. Enter... Map def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) => cons(f(head), tail) }
  • 76. Enter... Map def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) => cons(f(head), tail) } def foldRight[B](z: => B)(f: (A, => B) => B): B
  • 77. Enter... Map St r ea def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) => cons(f(head), tail) } Stream! St r ea m St r ! ea m m ! ! def foldRight[B](z: => B)(f: (A, => B) => B): B
  • 79. Enter... Filter def filter(p: A => Boolean): Stream[A] = foldRight(empty[A]) { (head, tail) => if (p(head)) cons(head, tail) else tail }
  • 80. Enter... Filter def filter(p: A => Boolean): Stream[A] = foldRight(empty[A]) { (head, tail) => if (p(head)) cons(head, tail) else tail } def foldRight[B](z: => B)(f: (A, => B) => B): B
  • 81. Enter... Filter def filter(p: A => Boolean): Stream[A] = foldRight(empty[A]) { (head, tail) => if (p(head)) cons(head, tail) else tail St re } am Stream! ! St r ea St r ea m m ! def foldRight[B](z: => B)(f: (A, => B) => B): B !
  • 83. Returning Streams Both map and filter return Streams
  • 84. Returning Streams Both map and filter return Streams Stream’s constructors eval neither head nor tail
  • 85. Returning Streams Both map and filter return Streams Stream’s constructors eval neither head nor tail This allows for the chaining of laziness from the by name parameter of foldRight, into the return value
  • 87. Returning Streams def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) =>
  • 88. Returning Streams def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) => Not Eval’d
  • 89. Returning Streams def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) => ! ! ! Not Eval’d ! Not Eval’d ! cons(f(head), tail) }
  • 90. Returning Streams def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) => ! ! ! Not Eval’d Not Eval’d ! Not Eval’d ! cons(f(head), tail) }
  • 91. Returning Streams def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) => ! ! ! Not Eval’d Not Eval’d ! Not Eval’d ! cons(f(head), tail) } Jeez, does this code even do anything!?
  • 93. Let’s find Out... Stream(1, 2, 3, 4, 5) map { i => println(s"map -> $i") i * i }
  • 94. Let’s find Out... Stream(1, 2, 3, 4, 5) map { i => println(s"map -> $i") i * i } Which prints... def map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) => cons(f(head), tail) } Remember that... and... def foldRight[B](z: => B)(f: (A, => B) => B): B def cons[A](hd: => A, tl: => Stream[A]): Stream[A] and...
  • 96. Putting it All Together
  • 97. Putting it All Together val s = Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 }
  • 98. Putting it All Together val s = Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 } Prints nothing. OK
  • 99. Putting it All Together val s = Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 } def toList: List[A] = uncons match { case None => Nil case Some((h, t)) => h :: t.toList } Prints nothing. OK add toList()
  • 102. Evaluating val numList = s.toList // // // // // // // stream stream stream stream ... stream stream -> -> -> -> map 1 filter 11 map 2 filter 12 -> map 10 -> filter 20
  • 103. Evaluating val numList = s.toList def take(n: Int): Stream[A] = uncons match { case Some((h, t)) if n > 0 => cons(h, t.take(n - 1)) case _ => empty } // // // // // // // stream stream stream stream ... stream stream -> -> -> -> map 1 filter 11 map 2 filter 12 -> map 10 -> filter 20
  • 104. Evaluating val numList = s.toList def take(n: Int): Stream[A] = uncons match { case Some((h, t)) if n > 0 => cons(h, t.take(n - 1)) case _ => empty } val numList = s.take(1).toList // // // // // // // stream stream stream stream ... stream stream -> -> -> -> map 1 filter 11 map 2 filter 12 -> map 10 -> filter 20
  • 105. Evaluating val numList = s.toList def take(n: Int): Stream[A] = uncons match { case Some((h, t)) if n > 0 => cons(h, t.take(n - 1)) case _ => empty } val numList = s.take(1).toList // // // // // // // stream stream stream stream ... stream stream // // // // -> -> -> -> map 1 filter 11 map 2 filter 12 -> map 10 -> filter 20 stream stream stream stream -> -> -> -> map 1 filter 11 map 2 filter 12
  • 106. It’s All About Functions
  • 107. It’s All About Functions Functions hold the values
  • 108. It’s All About Functions Functions hold the values Higher order functions pile functions on functions
  • 109. It’s All About Functions Functions hold the values Higher order functions pile functions on functions Even functions like take() merely store functions
  • 110. It’s All About Functions Functions hold the values Higher order functions pile functions on functions Even functions like take() merely store functions Nothing “real” happens until you need it to happen
  • 111. It’s All About Functions Functions hold the values Higher order functions pile functions on functions Even functions like take() merely store functions Nothing “real” happens until you need it to happen ! y in h S
  • 112. ms rea St ss yA az L i Brought to you Sincere Couch Potato em s Derek Wyatt Twitter: @derekwyatt Email: derek@derekwyatt.org