Slide 1

Slide 1 text

){}w ile(){}w {}while(){}w le(){}while(){}w }while(){}while(){}w e(){}while(){}while(){}w while(){}while(){}while(){}w (){}while(){}while(){}while(){}w hile(){}while(){}while(){}while(){}w ){}while(){}while(){}while(){}while(){}w ile(){}while(){}while(){}while(){}while(){}w {}while(){}while(){}while(){}while(){}while(){}w 都什麼時代了 你還在寫 while loop 嗎? INFECTED PROGRAM WHILE LOOP @pishen

Slide 2

Slide 2 text

Pishen Vpon 5 years Scala Scala Taiwan Open Source VocaRadio sbt-lighter annoy4s AkkaUI Gitter Facebook Scala Kitchen 日本 Scala 旅遊團 https://gitter.im/ScalaTaiwan/ScalaTaiwan https://www.facebook.com/groups/ScalaTW/ https://www.meetup.com/Scala-Taiwan-Meetup/ Meetup (each month) Since 2015 冬

Slide 3

Slide 3 text

2018-10-19 2018-12-31 ?

Slide 4

Slide 4 text

2018-10-19 2018-12-31 2018-10-20 2018-10-21 2018-10-22 • • • 2018-12-28 2018-12-30 2018-12-29

Slide 5

Slide 5 text

Solution 1: While Loop

Slide 6

Slide 6 text

var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates) java.time.LocalDate

Slide 7

Slide 7 text

var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates)

Slide 8

Slide 8 text

var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates) append List(1,2,3) :+ 4 List(1,2,3,4)

Slide 9

Slide 9 text

var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates)

Slide 10

Slide 10 text

var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates) dates.length == x dates.length == x + 1

Slide 11

Slide 11 text

var dates = List(startDate) //while (dates.last.isBefore(endDate)) { // // // dates = dates :+ dates.last.plusDays(1) // // //} println(dates) ✔ Compiler still pass! dates.length == x dates.length == x + 1

Slide 12

Slide 12 text

var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates) dates.length == x dates.length == x + 1

Slide 13

Slide 13 text

var dates = List(startDate) println(dates) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } dates.length == x dates.length == x + 1 ✔ Compiler still pass!

Slide 14

Slide 14 text

var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates) dates.length == x dates.length == x + 1 An optional part of code that *will* change the program's behavior. ?

Slide 15

Slide 15 text

1970s Don't use GOTO 1995 25 years GOTO is prohibited! https://en.wikipedia.org/wiki/Goto 2018 23 years Don't use while

Slide 16

Slide 16 text

Solution 2: Tail Recursion

Slide 17

Slide 17 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates)

Slide 18

Slide 18 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates)

Slide 19

Slide 19 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates)

Slide 20

Slide 20 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates) return You don't have to write "return" in Scala's function.

Slide 21

Slide 21 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates) iterate [d1,d2,d3,d4,d5] iterate [d1] iterate [d1,d2] iterate [d1,d2,d3] iterate [d1,d2,d3,d4] [d1,d2,d3,d4,d5] [d1,d2,d3,d4,d5] [d1,d2,d3,d4,d5] [d1,d2,d3,d4,d5] [d1,d2,d3,d4,d5]

Slide 22

Slide 22 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates)

Slide 23

Slide 23 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates)

Slide 24

Slide 24 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates) dates.length == x

Slide 25

Slide 25 text

//def iterate(dates: List[LocalDate]): List[LocalDate] = { // if (dates.last.isBefore(endDate)) { // iterate(dates :+ dates.last.plusDays(1)) // } else { // dates // } //} val dates = iterate(List(startDate)) println(dates) ✗ Compile Error!

Slide 26

Slide 26 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates)

Slide 27

Slide 27 text

val dates = iterate(List(startDate)) def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } println(dates) ✗ Compile Error!

Slide 28

Slide 28 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates) An explicit part of code for easier code tracing.

Slide 29

Slide 29 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates) var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates)

Slide 30

Slide 30 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates) var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates)

Slide 31

Slide 31 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } val dates = iterate(List(startDate)) println(dates) var dates = List(startDate) while (dates.last.isBefore(endDate)) { dates = dates :+ dates.last.plusDays(1) } println(dates)

Slide 32

Slide 32 text

def iterate(dates: List[LocalDate]): List[LocalDate] = { if (dates.last.isBefore(endDate)) { iterate(dates :+ dates.last.plusDays(1)) } else { dates } } Tail Recursion Only call yourself at the last position. Tail Call Optimization Prevent memory from stack overflow. https://en.wikipedia.org/wiki/Tail_call https://www.artima.com/pins1ed/functions-and-closures.html#8.9 Not available in Java ⚠

Slide 33

Slide 33 text

Solution 3: Stream

Slide 34

Slide 34 text

1 2 3 4 5 6 7 val numbers = Stream.range(1, 8) Not evaluated (Take no memory)

Slide 35

Slide 35 text

1 2 3 4 5 6 7 Not evaluated (Take no memory) val numbers = Stream.range(1, 8) val n2 = numbers(2)

Slide 36

Slide 36 text

1 2 3 4 5 6 7 val numbers = Stream.range(1, 8) val n2 = numbers(2) Memoization

Slide 37

Slide 37 text

1 2 3 4 5 6 7 val numbers = Stream.range(1, 8) val n2 = numbers(2) val n4 = numbers(4) Memoization

Slide 38

Slide 38 text

1 2 3 4 5 6 7 Memoization val numbers = Stream.range(1, 8) val n2 = numbers(2) val n4 = numbers(4)

Slide 39

Slide 39 text

1 2 3 4 5 6 7 val numbers = Stream.range(1, 8) val n2 = numbers(2) val n4 = numbers(4) val list = numbers.toList

Slide 40

Slide 40 text

val numbers = Stream.range(1, 8) val n2 = numbers(2) val n4 = numbers(4) val list = numbers.toList 1 2 3 4 5 6 7 1 2 3 4 5 6 7 list

Slide 41

Slide 41 text

Stream.continually(1) Stream.iterate(0)(x => x + 2) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 2 4 6 8 10 12 14 16 18 20 2 +2 +2 +2 Stream.continually(List(1,2,3)).flatten 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 lambda function

Slide 42

Slide 42 text

stream.map(x => x * 2) 1 2 3 4 5 6 7 8 9 10 11 1 2 4 6 8 10 12 14 16 18 20 22 2

Slide 43

Slide 43 text

stream.filter(x => x % 2 == 1) 1 2 3 4 5 6 7 8 9 10 11 1 1 3 5 7 9 11 13 15 17 19 21 2

Slide 44

Slide 44 text

stream.flatMap(x => List(x, x)) 1 2 3 4 5 6 7 8 9 10 11 1 1 1 2 2 3 3 4 4 5 5 6 1 1 2 2 3 3 4 4 5 5 6 6

Slide 45

Slide 45 text

stream.take(5) 1 2 3 4 5 6 7 8 9 10 11 1 1 2 3 4 5

Slide 46

Slide 46 text

stream.takeWhile(x => x < 6) 1 2 3 4 5 6 7 8 9 10 11 1 1 2 3 4 5

Slide 47

Slide 47 text

val dates = Stream.iterate(startDate)(_.plusDays(1)) x => x.plusDays(1) plusDays(1) d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11

Slide 48

Slide 48 text

val dates = Stream.iterate(startDate)(_.plusDays(1)) .takeWhile(_.isBefore(endDate.plusDays(1))) d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 endDate d1 d2 d3 d4 d5 d6 d7 d8 d9 dates

Slide 49

Slide 49 text

val dates = Stream.iterate(startDate)(_.plusDays(1)) .takeWhile(_.isBefore(endDate.plusDays(1))) println(dates.toList)

Slide 50

Slide 50 text

val numbers = Stream.iterate(0)(_ + 1) val n3 = numbers(3) 1 2 3 4 5 6 7 8 9 10 11 1 val numbers = Iterator.iterate(0)(_ + 1) val n3 = numbers(3) 1 2 3 4 5 6 7 8 9 10 11 1 Works like Java's Stream Memoization

Slide 51

Slide 51 text

1 2 3 4 5 6 7 Stream.range(1, 8) LazyList.range(1, 8) 1 2 3 4 5 6 7 Scala 2.13.0 (fully lazy)

Slide 52

Slide 52 text

Example 1: Auto Pager

Slide 53

Slide 53 text

val page: Page = getFirstPage() val items: List[Item] = page.getItems() val hasNext: Boolean = page.hasNextPage() val nextPage: Page = page.getNextPage() May return null if Page doesn't exist. Given a number n, please return first n items to me?

Slide 54

Slide 54 text

def take(n: Int): List[Item] = { var page = getFirstPage() if (page != null) { var items = page.getItems() while(page.hasNextPage() && items.size < n) { page = page.getNextPage() items = items ++ page.getItems() } items.take(n) } else { List.empty[Item] } }

Slide 55

Slide 55 text

val items = Stream .iterate(getFirstPage())(_.getNextPage) .takeWhile(_ != null) .flatMap(_.getItems) p1 p2 p3 null getNextPage() Exceptions p1 p2 p3 takeWhile() i1 i2 i3 i4 i5 i6 i7 i8 i9 flatMap() items.take(5)

Slide 56

Slide 56 text

val items = Stream .iterate(getFirstPage())(_.getNextPage) .takeWhile(_ != null) .flatMap(_.getItems) p1 p2 p3 null getNextPage() Exceptions p1 p2 p3 takeWhile() i1 i2 i3 i4 i5 i6 i7 i8 i9 flatMap() items.take(5) items.take(8)

Slide 57

Slide 57 text

val items = Stream .iterate(getFirstPage())(_.getNextPage) .takeWhile(_ != null) .flatMap(_.getItems) p1 p2 p3 null getNextPage() Exceptions p1 p2 p3 takeWhile() i1 i2 i3 i4 i5 i6 i7 i8 i9 flatMap() items.take(5) items.take(8)

Slide 58

Slide 58 text

Example 2: Fibonacci Sequence

Slide 59

Slide 59 text

stream.tail 1 2 3 4 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 1

Slide 60

Slide 60 text

streamA.zip(streamB) 1 2 3 4 5 6 7 8 9 10 11 streamA 1 2 3 1 2 3 1 2 3 1 2 streamB

Slide 61

Slide 61 text

streamA.zip(streamB).map { case (a, b) => a + b } 1 2 3 4 5 6 7 8 9 10 11 streamA 1 2 3 1 2 3 1 2 3 1 2 streamB 2 4 6 5 7 9 8 10 12 11 13

Slide 62

Slide 62 text

val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b } 0 1 fibs 0 1 fibs 1 fibs.tail

Slide 63

Slide 63 text

val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b } 0 1 1 0 1 1 fibs fibs fibs.tail

Slide 64

Slide 64 text

val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b } 0 1 1 0 1 1 1 1 fibs fibs fibs.tail

Slide 65

Slide 65 text

val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b } 0 1 1 2 0 1 1 1 1 fibs fibs fibs.tail

Slide 66

Slide 66 text

val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b } 0 1 1 2 0 1 1 2 1 1 2 fibs fibs fibs.tail

Slide 67

Slide 67 text

val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b } 0 1 1 2 3 0 1 1 2 1 1 2 fibs fibs fibs.tail

Slide 68

Slide 68 text

val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b } 0 1 1 2 3 0 1 1 2 3 1 1 2 3 fibs fibs fibs.tail

Slide 69

Slide 69 text

val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b } 0 1 1 2 3 5 8 13 21 34 55 0 1 1 2 3 5 8 13 21 1 1 2 3 5 8 13 21 34 fibs fibs fibs.tail

Slide 70

Slide 70 text

T h a n k Y o u