building a functional stream in scala
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 2: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/2.jpg)
A Functional Data Structure
![Page 3: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/3.jpg)
A Functional Data StructureStreams are andinfinite lazy
![Page 4: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/4.jpg)
A Functional Data StructureStreams are andinfinite lazy
They can be built using functions
![Page 5: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/5.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/6.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/7.jpg)
vs.Strictness Laziness
![Page 8: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/8.jpg)
vs.Strictness Lazinessdef strict(row: DBRow): Unit = { if (somecondition) // do something with row}
![Page 9: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/9.jpg)
vs.Strictness Lazinessdef strict(row: DBRow): Unit = { if (somecondition) // do something with row}
fetchRow(42)
![Page 10: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/10.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/11.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/12.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/13.jpg)
List: A “Strict” Data Type
![Page 14: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/14.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/15.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/16.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/17.jpg)
Streams: Lazy Ass Seqs
![Page 18: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/18.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/19.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/20.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/21.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/22.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/23.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/24.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/25.jpg)
Stream Definition
![Page 26: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/26.jpg)
Stream Definitiontrait Stream[+A] { def uncons: Option[(A, Stream[A])] }
![Page 27: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/27.jpg)
Stream Definitiontrait Stream[+A] { def uncons: Option[(A, Stream[A])] }
The “data” structure
![Page 28: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/28.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/29.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/30.jpg)
Constructing Streams
![Page 31: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/31.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/32.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/33.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/34.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/35.jpg)
The Stream... so far
![Page 36: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/36.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/37.jpg)
foldRight (does it all)(1 to 4).foldRight(z)(f)
![Page 38: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/38.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/39.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/40.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/41.jpg)
foldRight for Lists
![Page 42: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/42.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/43.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/44.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/45.jpg)
Strictly Folding Right
![Page 46: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/46.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/47.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/48.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/49.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/50.jpg)
Building foldRight
![Page 51: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/51.jpg)
trait Stream[+A] { def foldRight[B](z: ? B)(f: (A, ? B) => B): B }
Building foldRight
![Page 52: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/52.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/53.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/54.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/55.jpg)
Learning to Relax
![Page 56: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/56.jpg)
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B
![Page 57: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/57.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/58.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/59.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/60.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/61.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/62.jpg)
Learning to Relax
![Page 63: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/63.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/64.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/65.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/66.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/67.jpg)
Learning to Relax
![Page 68: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/68.jpg)
Learning to Relax
def foldRight[B](z: => B)(f: (A, => B) => B): B
![Page 69: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/69.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/70.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/71.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/72.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/73.jpg)
A Match Made in Laziness
=> + Non-Strict Result = Lazy
Stream
![Page 74: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/74.jpg)
Enter... Map
![Page 75: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/75.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/76.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/77.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/78.jpg)
Enter... Filter
![Page 79: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/79.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/80.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/81.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/82.jpg)
Returning Streams
![Page 83: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/83.jpg)
Returning StreamsBoth map and filter return Streams
![Page 84: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/84.jpg)
Returning StreamsBoth map and filter return Streams
Stream’s constructors eval neither head nor tail
![Page 85: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/85.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/86.jpg)
Returning Streams
![Page 87: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/87.jpg)
Returning Streamsdef map[T](f: A => T): Stream[T] = foldRight(empty[T]) { (head, tail) =>
![Page 88: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/88.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/89.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/90.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/91.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/92.jpg)
Let’s find Out...
![Page 93: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/93.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/94.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/95.jpg)
This page intentionally left blank
![Page 96: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/96.jpg)
Putting it All Together
![Page 97: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/97.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/98.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/99.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/100.jpg)
Evaluating
![Page 101: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/101.jpg)
Evaluatingval numList = s.toList
![Page 102: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/102.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/103.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/104.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/105.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/106.jpg)
It’s All About Functions
![Page 107: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/107.jpg)
It’s All About Functions
Functions hold the values
![Page 108: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/108.jpg)
It’s All About Functions
Functions hold the values
Higher order functions pile functions on functions
![Page 109: Building a Functional Stream in Scala](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/109.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/110.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/111.jpg)
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](https://reader031.vdocuments.us/reader031/viewer/2022020122/5549aa7eb4c9050c708b56db/html5/thumbnails/112.jpg)
Derek WyattTwitter: @derekwyatt
Email: [email protected]
Lazy Ass Streams
Brought to you Sincere Couch Potato
semi