Slide 1

Slide 1 text

Lazy Evaluation in Swift

Slide 2

Slide 2 text

• ΪΞ • @nghialv (twitter: nghialv2607) ΞΧ΢ϯτ • 2014೥11݄ʹCyberAgentʹ৽ଔೖࣾ • AmebaΞϓϦνʔϜ

Slide 3

Slide 3 text

A programming language uses an evaluation strategy to determine when to evaluate the argument(s) of a function call (for function, also read: operation, method, or relation) and what kind of value to pass to the function. “Wikipedia” Evaluation Strategy:

Slide 4

Slide 4 text

A programming language uses an evaluation strategy to determine when to evaluate the argument(s) of a function call (for function, also read: operation, method, or relation) and what kind of value to pass to the function. “Wikipedia” Evaluation Strategy: call-by-value call-by-reference

Slide 5

Slide 5 text

When?

Slide 6

Slide 6 text

Eager evaluation Call-by-name Call-by-need

Slide 7

Slide 7 text

Eager Evaluation func dosomething() -> Int { println("dosomething") return 1 } func foo(x: Int, status: String) { println("foo") } foo(dosomething(), "200") output dosomething foo

Slide 8

Slide 8 text

Eager Evaluation func dosomething() -> Int { println("dosomething") return 1 } func foo(x: Int, status: String) { println("foo") } foo(dosomething(), "200") output dosomething foo fooؔ਺ͷ࣮ߦલʹdosomething͕ධՁ͞ΕΔ

Slide 9

Slide 9 text

Eager Evaluation func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: Int, status: String) { println("foo") let result = status == "200" ? x : 0 println("result: \(result)") } foo(expensiveComputation(), "404") output expensiveComputation foo result: 0

Slide 10

Slide 10 text

Eager Evaluation func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: Int, status: String) { println("foo") let result = status == "200" ? x : 0 println("result: \(result)") } foo(expensiveComputation(), "404") output expensiveComputation foo result: 0 x ͕࢖ΘΕ͍ͯͳ͍ͷʹධՁ͞Εͨʂ

Slide 11

Slide 11 text

Eager Evaluation func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: Int, status: String) { println("foo") let result = status == "200" ? x : 0 println("result: \(result)") } foo(expensiveComputation(), "404") output expensiveComputation foo result: 0 x ͕࢖ΘΕ͍ͯͳ͍ͷʹධՁ͞Εͨʂ ϞολΠφΠʂ

Slide 12

Slide 12 text

Function Currying func dosomething() -> Int { println("dosomething") return 1 } func foo(a: Int)(b: Int) { println("add") } let cFoo = foo(dosomething()) //cFoo(b: 10) output dosomething

Slide 13

Slide 13 text

Function Currying func dosomething() -> Int { println("dosomething") return 1 } func foo(a: Int)(b: Int) { println("add") } let cFoo = foo(dosomething()) //cFoo(b: 10) output dosomething ͜ͷ࣌఺ʹ a ͕ධՁ͞ΕΔ

Slide 14

Slide 14 text

ඞཁ࣌ͷΈධՁ͍ͨ͠ʂ ධՁλΠϛϯάมߋ͍ͨ͠ʂ

Slide 15

Slide 15 text

Call-by-name ඞཁ࣌ͷΈධՁ͍ͨ͠ʂ ධՁλΠϛϯάมߋ͍ͨ͠ʂ

Slide 16

Slide 16 text

Call-by-name func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: () -> Int, status: String) { println("foo") let result = status == "200" ? x() : 0 println("result: \(result)") } foo({ expensiveComputation() }, "404") output foo result: 0

Slide 17

Slide 17 text

Call-by-name func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: () -> Int, status: String) { println("foo") let result = status == "200" ? x() : 0 println("result: \(result)") } foo({ expensiveComputation() }, "404") output foo result: 0 ClosureΛ࢖͏ʂ

Slide 18

Slide 18 text

Call-by-name func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: () -> Int, status: String) { println("foo") let result = status == "200" ? x() : 0 println("result: \(result)") } foo({ expensiveComputation() }, "404") output foo result: 0 ClosureΛ࢖͏ʂ ؾ࣋ͪѱ͍

Slide 19

Slide 19 text

@autoclosure

Slide 20

Slide 20 text

Call-by-name func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: @autoclosure () -> Int, status: String) { println("foo") let result = status == "200" ? x() : 0 println("result: \(result)") } foo(expensiveComputation(), "404") output foo result: 0

Slide 21

Slide 21 text

Call-by-name func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: @autoclosure () -> Int, status: String) { println("foo") let result = status == "200" ? x() : 0 println("result: \(result)") } foo(expensiveComputation(), "404") output foo result: 0 ؾ࣋ͪྑ͘ͳͬͨʂ

Slide 22

Slide 22 text

Call-by-name func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: @autoclosure () -> Int, status: String) { println("foo") let result = status == "200" ? x() : 0 let t1 = x() let t2 = x() println("result: \(result)") } foo(expensiveComputation(), "404") output foo expensiveComputation expensiveComputation result: 0

Slide 23

Slide 23 text

Call-by-name func expensiveComputation() -> Int { println("expensiveComputation") return 1 } func foo(x: @autoclosure () -> Int, status: String) { println("foo") let result = status == "200" ? x() : 0 let t1 = x() let t2 = x() println("result: \(result)") } foo(expensiveComputation(), "404") output foo expensiveComputation expensiveComputation result: 0 x ͕࠶ධՁ͞ΕΔʂ

Slide 24

Slide 24 text

࠶ධՁΛආ͚͍ͨʂ

Slide 25

Slide 25 text

Call-by-need ࠶ධՁΛආ͚͍ͨʂ

Slide 26

Slide 26 text

Call-by-need lazy property

Slide 27

Slide 27 text

Call-by-need class Foo { lazy var tmp: Int = { println("tmp init") return 1 }() } println("before init") let foo = Foo() println("after init") foo.tmp foo.tmp output before init after init tmp init

Slide 28

Slide 28 text

Call-by-need class Foo { lazy var tmp: Int = { println("tmp init") return 1 }() } println("before init") let foo = Foo() println("after init") foo.tmp foo.tmp output before init after init tmp init ̎ճݺ͹Ε͍ͯΔ͚ͲɼॳظԽ͸̍ճ͚ͩ ඞཁ࣌ͷΈධՁ͢Δ

Slide 29

Slide 29 text

Call-by-need lazy property global variable static property struct Foo { static var tmp: Int = { println("tmp init") return 1 }() static func log() { println("foo") } } let foo = Foo() Foo.log() println("access tmp") let x = Foo.tmp output foo access tmp tmp init

Slide 30

Slide 30 text

Memoization func memoize( body: (T)->U ) -> (T)->U { var memo = Dictionary() return { x in if let q = memo[x] { return q } let r = body(x) memo[x] = r return r } } Fibonacci link: WWDC2014 Advanced Swift (from page 123) Ωϟογϡ͞ΕͨͷͰ࠶ܭࢉ͕ෆཁ

Slide 31

Slide 31 text

When • Eager evaluation • evaluated completely before the function is applied • Call-by-name • evaluate only when needed • evaluate each time value is accessed • Call-by-need • evaluate only when needed • cache result for repeated access

Slide 32

Slide 32 text

͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠