building a functional stream in scala

112
Building A Functional Stream in Scala Derek Wyatt Twitter: @derekwyatt Email: [email protected]

Upload: derek-wyatt

Post on 06-May-2015

2.320 views

Category:

Technology


2 download

DESCRIPTION

I gave this presentation to my local Scala Meetup on Feb 12th 2014. It presents an aspect of functional programming by implementing a lazy data structure for storing an infinite collection of data. The act of building the stream is the point - you wouldn't use this in real life. The design for the stream is largely taken from Manning's "Functional Programming in Scala" by Paul Chiusano and Rúnar Bjarnason. Have a look at the book at http://www.manning.com/bjarnason/.

TRANSCRIPT

Page 1: Building a Functional Stream in Scala

BuildingA

Functional Streamin Scala

Derek WyattTwitter: @derekwyatt

Email: [email protected]

Page 2: Building a Functional Stream in Scala

A Functional Data Structure

Page 3: Building a Functional Stream in Scala

A Functional Data StructureStreams are andinfinite lazy

Page 4: Building a Functional Stream in Scala

A Functional Data StructureStreams are andinfinite lazy

They can be built using functions

Page 5: Building a Functional Stream in Scala

A Functional Data StructureStreams are andinfinite lazy

They can be built using functionsDesigning one is fun and instructive

Page 6: Building a Functional Stream in Scala

A Functional Data StructureStreams are andinfinite lazy

They can be built using functionsDesigning 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 Scalaby Paul Chiusano and Rúnar Bjarnason

Page 7: Building a Functional Stream in Scala

vs.Strictness Laziness

Page 8: Building a Functional Stream in Scala

vs.Strictness Lazinessdef strict(row: DBRow): Unit = { if (somecondition) // do something with row}

Page 9: Building a Functional Stream in Scala

vs.Strictness Lazinessdef strict(row: DBRow): Unit = { if (somecondition) // do something with row}

fetchRow(42)

Page 10: Building a Functional Stream in Scala

vs.Strictness Lazinessdef strict(row: DBRow): Unit = { if (somecondition) // do something with row}

fetchRow(42)

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

Page 11: Building a Functional Stream in Scala

vs.Strictness Lazinessdef strict(row: DBRow): Unit = { if (somecondition) // do something with row}

fetchRow(42)

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

somecond

ition =

false

Page 12: Building a Functional Stream in Scala

vs.Strictness Lazinessdef strict(row: DBRow): Unit = { if (somecondition) // do something with row}

fetchRow(42)

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

somecond

ition =

false

evaluated

Not Evaluated

Page 13: Building a Functional Stream in Scala

List: A “Strict” Data Type

Page 14: Building a Functional Stream in Scala

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

Page 15: Building a Functional Stream in Scala

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

[11, 12, ... 20]Map

// list -> map 1// list -> map 2// ...// list -> map 9// list -> map 10

Page 16: Building a Functional Stream in Scala

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

[11, 12, ... 20]Map

[12, 14, ... 20]Filter

// list -> map 1// list -> map 2// ...// list -> map 9// list -> map 10

// list -> map 1// list -> map 2// ...// list -> map 9// list -> map 10// list -> filter 11// list -> filter 12// ...// list -> filter 19// list -> filter 20

Page 17: Building a Functional Stream in Scala

Streams: Lazy Ass Seqs

Page 18: Building a Functional Stream in Scala

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

Page 19: Building a Functional Stream in Scala

Streams: Lazy Ass SeqsStream(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)

Page 20: Building a Functional Stream in Scala

Streams: Lazy Ass SeqsStream(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)

Map[11, ?]

Page 21: Building a Functional Stream in Scala

Streams: Lazy Ass SeqsStream(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)

The ?‘s are, essentiallyfunctions

Map[11, ?]Filter[12, ?]

Page 22: Building a Functional Stream in Scala

Streams: Lazy Ass SeqsStream(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)

The ?‘s are, essentiallyfunctions

Map[11, ?]Filter[12, ?]

For illustrative purposes only

Page 23: Building a Functional Stream in Scala

Streams: Lazy Ass SeqsStream(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)

The ?‘s are, essentiallyfunctions

Map[11, ?]Filter[12, ?]

Stream transformation does not require traversalFor illustrative purposes only

Page 24: Building a Functional Stream in Scala

Streams: Lazy Ass SeqsStream(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)

The ?‘s are, essentiallyfunctions

Map[11, ?]Filter[12, ?]

Stream transformation does not require traversalTransformations are applied on-demand as traversal happens

For illustrative purposes only

Page 25: Building a Functional Stream in Scala

Stream Definition

Page 26: Building a Functional Stream in Scala

Stream Definitiontrait Stream[+A] { def uncons: Option[(A, Stream[A])] }

Page 27: Building a Functional Stream in Scala

Stream Definitiontrait Stream[+A] { def uncons: Option[(A, Stream[A])] }

The “data” structure

Page 28: Building a Functional Stream in Scala

Stream Definitiontrait 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)) } }

The “data” structure

Constructors

Page 29: Building a Functional Stream in Scala

Stream Definitiontrait 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)) } }

The “data” structure

Constructors

Page 30: Building a Functional Stream in Scala

Constructing Streams

Page 31: Building a Functional Stream in Scala

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

Page 32: Building a Functional Stream in Scala

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

Well, that SUCKS...

Page 33: Building a Functional Stream in Scala

Constructing Streamsval 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:_*)) } }

Page 34: Building a Functional Stream in Scala

Constructing Streamsval 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:_*)) } }

val three = Stream(1, 2, 3)

Page 35: Building a Functional Stream in Scala

The Stream... so far

Page 36: Building a Functional Stream in Scala

The Stream... so fartrait 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:_*)) } }

Page 37: Building a Functional Stream in Scala

foldRight (does it all)(1 to 4).foldRight(z)(f)

Page 38: Building a Functional Stream in Scala

foldRight (does it all)

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

(1 to 4).foldRight(z)(f)

makes

Page 39: Building a Functional Stream in Scala

foldRight (does it all)

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

(1 to 4).foldRight(z)(f)

makes

f(1, ... f(1, f(2, ... f(1, f(2, f(3, ... f(1, f(2, f(3, f(4, z)))) f(1, f(2, f(3, res1))) f(1, f(2, res2)) f(1, res3) res4

or

Page 40: Building a Functional Stream in Scala

foldRight (does it all)

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

(1 to 4).foldRight(z)(f)

makes

f(1, ... f(1, f(2, ... f(1, f(2, f(3, ... f(1, f(2, f(3, f(4, z)))) f(1, f(2, f(3, res1))) f(1, f(2, res2)) f(1, res3) res4

or

Builds a functional structure “to the right”, pushing successive evaluation to the second parameter.

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

Page 41: Building a Functional Stream in Scala

foldRight for Lists

Page 42: Building a Functional Stream in Scala

foldRight for Listscase 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)) }

Page 43: Building a Functional Stream in Scala

foldRight for Listscase 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 = (1 to 4).foldRight(0)(_ + _) // f(1, tail.foldRight... // f(1, f(2, tail.foldRight... // f(1, f(2, f(3, tail.foldRight... // f(1, f(2, f(3, f(4, 0)))) // f(1, f(2, f(3, 4))) // f(1, f(2, 7)) // f(1, 9) // 10

Page 44: Building a Functional Stream in Scala

foldRight for Listscase 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 = (1 to 4).foldRight(0)(_ + _) // f(1, tail.foldRight... // f(1, f(2, tail.foldRight... // f(1, f(2, f(3, tail.foldRight... // f(1, f(2, f(3, f(4, 0)))) // f(1, f(2, f(3, 4))) // f(1, f(2, 7)) // f(1, 9) // 10

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

Page 45: Building a Functional Stream in Scala

Strictly Folding Right

Page 46: Building a Functional Stream in Scala

Strictly Folding Right℥ No application of ‘f’ can complete until all of its parameters

have been applied

Page 47: Building a Functional Stream in Scala

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

Page 48: Building a Functional Stream in Scala

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

Page 49: Building a Functional Stream in Scala

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

Page 50: Building a Functional Stream in Scala

Building foldRight

Page 51: Building a Functional Stream in Scala

trait Stream[+A] { def foldRight[B](z: ? B)(f: (A, ? B) => B): B }

Building foldRight

Page 52: Building a Functional Stream in Scala

trait Stream[+A] { def foldRight[B](z: ? B)(f: (A, ? B) => B): B }

trait Stream[+A] { def uncons: Option[(A, Stream[A])] ! 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

Page 53: Building a Functional Stream in Scala

trait Stream[+A] { def foldRight[B](z: ? B)(f: (A, ? B) => B): B }

trait Stream[+A] { def uncons: Option[(A, Stream[A])] ! 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

A profound change!A profound change!A profound change!A profound change!

Page 54: Building a Functional Stream in Scala

trait Stream[+A] { def foldRight[B](z: ? B)(f: (A, ? B) => B): B }

trait Stream[+A] { def uncons: Option[(A, Stream[A])] ! 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

The recursive call is no longer evaluated at the call site because ‘f’ receives it by name

Page 55: Building a Functional Stream in Scala

Learning to Relax

Page 56: Building a Functional Stream in Scala

Learning to Relax

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

Page 57: Building a Functional Stream in Scala

Learning to Relax

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

At this point, you’re potentially confused

Page 58: Building a Functional Stream in Scala

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?

Page 59: Building a Functional Stream in Scala

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)(_ + _)

Page 60: Building a Functional Stream in Scala

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)

Page 61: Building a Functional Stream in Scala

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)

Int is a “STRICT” Type!

Page 62: Building a Functional Stream in Scala

Learning to Relax

Page 63: Building a Functional Stream in Scala

Learning to RelaxOk, I kinda lied… it’s not that Int is a “strict type”(You can, of course, do something useful with an Int… such as)

Page 64: Building a Functional Stream in Scala

Learning to RelaxOk, 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)(_ + _)

Page 65: Building a Functional Stream in Scala

Learning to RelaxOk, I kinda lied… it’s not that Int is a “strict type”(You can, of course, do something useful with an Int… such as)

It’s just that the strict type can cause a bit of confusion because of its non-lazy nature.

def sumToN(ints: Stream[Int], to: Int): Int = ints.take(to).foldRight(0)(_ + _)

Page 66: Building a Functional Stream in Scala

Learning to RelaxOk, I kinda lied… it’s not that Int is a “strict type”(You can, of course, do something useful with an Int… such as)

It’s just that the strict type can cause a bit of confusion because of its non-lazy nature.

def sumToN(ints: Stream[Int], to: Int): Int = ints.take(to).foldRight(0)(_ + _)

The more “interesting” stuff, though happens when you can continue beings lazy and stay within the realm of the infinite

Page 67: Building a Functional Stream in Scala

Learning to Relax

Page 68: Building a Functional Stream in Scala

Learning to Relax

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

Page 69: Building a Functional Stream in Scala

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

Page 70: Building a Functional Stream in Scala

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

Page 71: Building a Functional Stream in Scala

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

However, you can’t just delay a computation without shoving it into some sort of context...

‘f’ can decide to delay the execution of its second parameter, eliminating the recursive call, returning control to the caller

Page 72: Building a Functional Stream in Scala

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

However, you can’t just delay a computation without shoving it into some sort of context...

‘f’ can decide to delay the execution of its second parameter, eliminating the recursive call, returning control to the caller

The STREAM

is that context!

Page 73: Building a Functional Stream in Scala

A Match Made in Laziness

=> + Non-Strict Result = Lazy

Stream

Page 74: Building a Functional Stream in Scala

Enter... Map

Page 75: Building a Functional Stream in Scala

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

Page 76: Building a Functional Stream in Scala

Enter... Mapdef 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

Page 77: Building a Functional Stream in Scala

Enter... Mapdef 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

Stream!Stream!

Stream!

Stream!

Page 78: Building a Functional Stream in Scala

Enter... Filter

Page 79: Building a Functional Stream in Scala

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

Page 80: Building a Functional Stream in Scala

Enter... Filterdef 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

Page 81: Building a Functional Stream in Scala

Enter... Filterdef 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

Stream!

Stream!

Stream!Stream!

Page 82: Building a Functional Stream in Scala

Returning Streams

Page 83: Building a Functional Stream in Scala

Returning StreamsBoth map and filter return Streams

Page 84: Building a Functional Stream in Scala

Returning StreamsBoth map and filter return Streams

Stream’s constructors eval neither head nor tail

Page 85: Building a Functional Stream in Scala

Returning StreamsBoth 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

Page 86: Building a Functional Stream in Scala

Returning Streams

Page 87: Building a Functional Stream in Scala

Returning Streamsdef map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) =>

Page 88: Building a Functional Stream in Scala

Returning Streamsdef map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) =>

Not Eval’d

Page 89: Building a Functional Stream in Scala

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

Not Eval’d

Not Eval’d

Page 90: Building a Functional Stream in Scala

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

Not Eval’d

Not Eval’d

Not Eval’d

Page 91: Building a Functional Stream in Scala

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

Not Eval’d

Not Eval’d

Not Eval’d

Jeez, does this code even do anything!?

Page 92: Building a Functional Stream in Scala

Let’s find Out...

Page 93: Building a Functional Stream in Scala

Let’s find Out...Stream(1, 2, 3, 4, 5) map { i => println(s"map -> $i") i * i }

Page 94: Building a Functional Stream in Scala

Let’s find Out...Stream(1, 2, 3, 4, 5) map { i => println(s"map -> $i") i * i }

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

Remember that...

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

def cons[A](hd: => A, tl: => Stream[A]): Stream[A]and...

Which prints...

Page 95: Building a Functional Stream in Scala

This page intentionally left blank

Page 96: Building a Functional Stream in Scala

Putting it All Together

Page 97: Building a Functional Stream in Scala

Putting it All Togetherval s = Stream(1 to 10) map { i => println(s”stream -> map $i”) i + 10 } filter { i => println(s”stream -> filter $i”) i % 2 == 0 }

Page 98: Building a Functional Stream in Scala

Putting it All Togetherval 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

Page 99: Building a Functional Stream in Scala

Putting it All Togetherval 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()

Page 100: Building a Functional Stream in Scala

Evaluating

Page 101: Building a Functional Stream in Scala

Evaluatingval numList = s.toList

Page 102: Building a Functional Stream in Scala

Evaluatingval numList = s.toList

// stream -> map 1// stream -> filter 11// stream -> map 2// stream -> filter 12// ...// stream -> map 10// stream -> filter 20

Page 103: Building a Functional Stream in Scala

Evaluatingval 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 -> map 1// stream -> filter 11// stream -> map 2// stream -> filter 12// ...// stream -> map 10// stream -> filter 20

Page 104: Building a Functional Stream in Scala

Evaluatingval 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 -> map 1// stream -> filter 11// stream -> map 2// stream -> filter 12// ...// stream -> map 10// stream -> filter 20

val numList = s.take(1).toList

Page 105: Building a Functional Stream in Scala

Evaluatingval 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 -> map 1// stream -> filter 11// stream -> map 2// stream -> filter 12// ...// stream -> map 10// stream -> filter 20

val numList = s.take(1).toList

// stream -> map 1// stream -> filter 11// stream -> map 2// stream -> filter 12

Page 106: Building a Functional Stream in Scala

It’s All About Functions

Page 107: Building a Functional Stream in Scala

It’s All About Functions

Functions hold the values

Page 108: Building a Functional Stream in Scala

It’s All About Functions

Functions hold the values

Higher order functions pile functions on functions

Page 109: Building a Functional Stream in Scala

It’s All About Functions

Functions hold the values

Higher order functions pile functions on functions

Even functions like take() merely store functions

Page 110: Building a Functional Stream in Scala

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

Page 111: Building a Functional Stream in Scala

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

Shiny!Shiny!Shiny!Shiny!

Page 112: Building a Functional Stream in Scala

Derek WyattTwitter: @derekwyatt

Email: [email protected]

Lazy Ass Streams

Brought to you Sincere Couch Potato

semi