Slide 1

Slide 1 text

@filippovitale May 2017 Ann Arbor FP Lazy Evaluation Haskell vs. Scala

Slide 2

Slide 2 text

From Useless to Nirvana

Slide 3

Slide 3 text

Effects Anywhere

Slide 4

Slide 4 text

https://www.youtube.com/watch?v=06x8Wf2r2Mc#t=21m52s Limited Controlled Effects Effects Anywhere

Slide 5

Slide 5 text

https://www.youtube.com/watch?v=06x8Wf2r2Mc#t=21m52s Limited Controlled Effects Effects Anywhere

Slide 6

Slide 6 text

https://www.youtube.com/watch?v=06x8Wf2r2Mc#t=21m52s Limited Controlled Effects Effects Anywhere Nirvana

Slide 7

Slide 7 text

https://www.youtube.com/watch?v=06x8Wf2r2Mc#t=21m52s Useful Limited Controlled Effects Effects Anywhere Nirvana

Slide 8

Slide 8 text

https://www.youtube.com/watch?v=06x8Wf2r2Mc#t=21m52s Useful Useless Limited Controlled Effects Effects Anywhere Nirvana

Slide 9

Slide 9 text

https://www.youtube.com/watch?v=06x8Wf2r2Mc#t=21m52s Useful Useless Limited Controlled Effects Effects Anywhere Nirvana

Slide 10

Slide 10 text

https://www.youtube.com/watch?v=06x8Wf2r2Mc#t=21m52s Useful Useless Limited Controlled Effects Effects Anywhere Nirvana

Slide 11

Slide 11 text

Effects & Evaluation Models

Slide 12

Slide 12 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered

Slide 13

Slide 13 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered - easy to predict when and in what order things will happen

Slide 14

Slide 14 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered - easy to predict when and in what order things will happen - f(release_monkeys(), increment_counter()) - it doesn't matter if `f` uses those results or not

Slide 15

Slide 15 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered When “side effects” are allowed, strict evaluation is really what you want.

Slide 16

Slide 16 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered Call-by-name - arguments are passed unevaluated

Slide 17

Slide 17 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered Call-by-name - arguments are passed unevaluated If an argument is not used in the function body ⇒ the argument is never evaluated If it is used several times ⇒ it is re-evaluated each time it appears

Slide 18

Slide 18 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered Call-by-name - arguments are passed unevaluated Call-by-need - arguments are passed unevaluated but an expression is only evaluated once and shared upon subsequent references http://dev.stephendiehl.com/fun/005_evaluation.html

Slide 19

Slide 19 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered Call-by-name - arguments are passed unevaluated Call-by-need - arguments are passed unevaluated but an expression is only evaluated once and shared upon subsequent references Lazy evaluation makes it hard to reason about when things will be evaluated Side effects in a lazy language would be extremely unintuitive Lazy evaluation strategy essentially forces you to also choose purity https://en.wikipedia.org/wiki/Evaluation_strategy

Slide 20

Slide 20 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered Call-by-name - arguments are passed unevaluated Call-by-need - arguments are passed unevaluated but an expression is only evaluated once and shared upon subsequent references In a “pure“ (effect-free) setting ⇒ this produces the same results as call-by-name https://en.wikipedia.org/wiki/Evaluation_strategy

Slide 21

Slide 21 text

Evaluation Models 3 dominant models: Call-by-value - arguments are evaluated: before a function is entered Call-by-name - arguments are passed unevaluated Call-by-need - arguments are passed unevaluated but an expression is only evaluated once and shared upon subsequent references In a “pure“ (effect-free) setting ⇒ this produces the same results as call-by-name (memoized version of call-by-name) Unevaluated expressions are represented by thunks https://en.wikipedia.org/wiki/Evaluation_strategy

Slide 22

Slide 22 text

Thunks

Slide 23

Slide 23 text

Thunks Unevaluated expressions in heap memory, built to postpone the Evaluation https://takenobu-hs.github.io/downloads/haskell_lazy_evaluation.pdf (pg. 68)

Slide 24

Slide 24 text

Thunks Unevaluated expressions in heap memory, built to postpone the Evaluation https://takenobu-hs.github.io/downloads/haskell_lazy_evaluation.pdf (pg. 68) Suspended Computations

Slide 25

Slide 25 text

Thunks GHC uses Thunks to achieve Laziness

Slide 26

Slide 26 text

GHC uses Thunks to achieve Laziness Thunks http://scalapuzzlers.com/#pzzlr-012 “...but wait, we have laziness in Scala too!”

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

λ> head [1, undefined] 1 scala> ??? scala.NotImplementedError

Slide 29

Slide 29 text

λ> head [1, undefined] 1 λ> rest = drop 1 [1, undefined] λ> :sp rest rest = _

Slide 30

Slide 30 text

λ> head [1, undefined] 1 λ> rest = drop 1 [1, undefined] λ> :sp rest rest = _ λ> print $ head rest [*** Exception: Prelude.undefined

Slide 31

Slide 31 text

λ> head [1, undefined] 1 λ> rest = drop 1 [1, undefined] λ> :sp rest rest = _ λ> print $ head rest [*** Exception: Prelude.undefined scala> val leroyJenkins = List(1, ???) scala.NotImplementedError

Slide 32

Slide 32 text

scala> lazy val a = 1 a: Int = scala> lazy val b = ??? b: Nothing = scala> List(a, b)

Slide 33

Slide 33 text

scala> lazy val a = 1 a: Int = scala> lazy val b = ??? b: Nothing = scala> List(a, b) scala.NotImplementedError

Slide 34

Slide 34 text

scala> val ethicList = 1 #:: ??? #:: Stream.empty immutable.Stream[Int] = Stream(1, ?) scala> ethicList.head res0: Int = 1

Slide 35

Slide 35 text

scala> val ethicList = 1 #:: ??? #:: Stream.empty immutable.Stream[Int] = Stream(1, ?) scala> ethicList.head res0: Int = 1 scala> ethicList.length scala.NotImplementedError

Slide 36

Slide 36 text

λ> :set -XMonomorphismRestriction λ> let ethicList = [1, undefined] λ> head ethicList 1 λ> length ethicList 2 λ> :sp ethicList ethicList = [1,_]

Slide 37

Slide 37 text

Thunks Scala is a multi-paradigm language ⇒ Imperative first https://www.quora.com/What-is-the-philosophy-of-functional-programming/answer/Tikhon-Jelvis?srid=Ezlj

Slide 38

Slide 38 text

Thunks Scala is a multi-paradigm language ⇒ Imperative first https://www.quora.com/What-is-the-philosophy-of-functional-programming/answer/Tikhon-Jelvis?srid=Ezlj Does the order in which expressions are evaluated matter?

Slide 39

Slide 39 text

Thunks Haskell is all about evaluation and simplification https://www.quora.com/What-is-the-philosophy-of-functional-programming/answer/Tikhon-Jelvis?srid=Ezlj

Slide 40

Slide 40 text

“Laziness allows you to express your thoughts concisely, letting the compiler figure out how to efficiently execute your code.”

Slide 41

Slide 41 text

@filippovitale May 2017 Ann Arbor FP Thanks!

Slide 42

Slide 42 text

Why make Haskell a non-strict language? - Separation of concerns without time penalty: WYSIWYG - Improved code reuse - Infinite data structures - Can make qualitative improvements to performance - Can hurt performance in some other cases - Makes code simpler - Makes hard problems conceivable - Allows for separation of concerns with regard to generating and processing data - Laziness often introduces an overhead that leads programmers to hunt for places where they can make their code more strict - The real benefit of laziness is in making the right things efficient enough - Lazy evaluation allows us to write more simple, elegant code than we could in a strict environment

Slide 43

Slide 43 text

“Hard work pays off later. Laziness pays off now!” – Steven Wright