code

2016年11月11日 星期五

Scala筆記 25 - Lazy Evaluation

三種evaluation modes

某個定義在使用到的時候才會被evaluate,並且儲存已經evaluate過的結果,所以不會重複evaluate同一個定義,這稱作lazy evaluation:

lazy val y = { print(”y”); 2 }

如果每次使用都會被evaluate一次,稱為by-name evaluation,這就是一般call by reference的參數:

def z = 4   //z: z[] => Int,這就是一個function
z           //res0: Int = 4,此時才被evaluate

最後一種就是strict evaluation,只要宣告時就馬上evaluate:

val x = { print(”x”); 1 }

之前的Stream cons的定義用到了by-name evaluation,這會變得非常慢,可以改成lazy evaluation就能避免這個問題,但是就會用到額外的記憶體空間:

def cons[T](hd: T, tl: => Stream[T]) = new Stream[T] {
  def head = hd
  lazy val tail = tl
  ...
}

Haskell default是使用lazy evaluation,但是Scala因為有mutable data types,所以怕造成不可預測的混亂,提供了optional的lazy evaluation。

所以以下的expr,如果被evaluate的話:

def expr = {
  val x = { print(”x”); 1 }
  lazy val y = { print(”y”); 2 }
  def z = { print(”z”); 3 }
  z + y + x + z + y + x
}

expr

1. 印出x,並且x被assigned成1
2. y不被evaluete,因為沒人用到它
3. z不被evaluate,因為沒人用到它
4. 開始evaluate z + y + x + z + y + x
5. evaluate z,印出z,z被mapped成3
6. evaluate y,印出y,且y被assigned成2,總共3+2
7. 取出x值,總共3+2+1
8. evaluate z,印出z,總共3+2+1+3
9. 取出y值,總共3+2+1+3+2
10. 取出x值,總共3+2+1+3+2+1

執行結果印出 xzyz,然後expr被evaluate成12

沒有留言:

張貼留言