KoreanFoodie's Study

Scala 2 - Blocks in Scala & Lazy val 본문

Tutorials/Scala

Scala 2 - Blocks in Scala & Lazy val

GoldGiver 2019. 4. 23. 18:56

 

스칼라 튜토리얼, scala에서 lazy val에 대해 알아보자


Blocks and Name Scoping

Blocks in scala

Block is an expression. It also allow nested name binding.

Block allows arbitraty order of "def"s, but not "val"s(think about why).


Scope of names

Block example :

val t = 0
def f(x: Int) = t + g(x)
def g(x: Int) = x * x
val x = f(5)
val r = {
    val t = 10
    val s = f(5)
    t + s
  }
val y = t + r

A definition inside a block is only accessible within the block.

A definition inside a block shadows definitions of the same name
outside the block.
A definition inside a block is accessible unless it is shadowed.

A function is evaluated under the environment where it is defined, not the environment where it is invoked(Important!).

Q. In the above code, what would be the result of 's' in 'r' block(at line 7)?

A. 25! Since function 'f' is evalueated as it is defined, because 't' is initialized as 0, therefore 'f' becomes same as 'g'.

Example: def with no arguments

val t = 0
def x = t+t   // is treated as def x() = t
val r = {
  val t = 10
  x }         // is treated as x(), r is 0.

Semi-colons and Parenthesis

Block

  • Can write two definitions/expressions in a single line using ;

  • Can write one definition/expression in two lines using (), but can omit () when clear

// ok
val r = {
  val t = 10; val s = square(5); t +
  s }
// Not ok
val r = {
  val t = 10; val s = square(5); t
  + s }
// ok
val r = {
  val t = 10; val s = square(5); (t
  + s) }

Exercise: Writing better code using blocks

  • Make the following code better
def isGoodEnough(guess: Double, x: Double) =
  guess*guess/x > 0.999 && guess*guess/x < 1.001

def improve(guess: Double, x: Double) =
  (guess + x/guess) / 2

def sqrtIter(guess: Double, x: Double): Double = {
  if (isGoodEnough(guess,x)) guess
  else sqrtIter(improve(guess,x),x)
}

def sqrt(x: Double) =
  sqrtIter(1, x)
sqrt(2)
  • Solution :
def sqrt(x: Double) = {

  def isGoodEnough(guess: Double, x: Double) =
   guess*guess/x > 0.999 && guess*guess/x < 1.001

  def improve(guess: Double, x: Double) =


  def sqrtIter(guess: Double, x: Double): Double = {
    if (isGoodEnough(guess,x)) guess
    else sqrtIter(improve(guess,x),x)
  }
  sqrtIter(1, x)
}

sqrt(2)

Lazy Call-By-Value

  • Use "lazy val"

  • Evaluate the expression first time it is used, then bind the name to it

def f(c: Boolean, i: =>Int): Int = {
  lazy val iv = i
  if (c) 0
  else iv * iv * iv
}

f(true, {println("ok"); 100+100+100+100})
f(false, {println("ok"); 100+100+100+100})

Q. What would output look like?

 

A. In console window, just single "ok".

If we remove 'lazy' from 'lazy val iv = i', then there will be 1 "ok"s(Since it is evaluated when it is initialized).

And if we replace 'lazy val' with 'def', there will be 3 "ok"s(only from second funtion call. It computes 'iv' during multiplicatoin every single time).

'Tutorials > Scala' 카테고리의 다른 글

Scala 6 - Datatypes  (0) 2019.04.23
Scala 5 - Currying  (0) 2019.04.23
Scala 4 - Closures, revisted  (0) 2019.04.23
Scala 3 - Tail Recursion & Higher-Order Functions 1  (0) 2019.04.23
Scala 1 - Call by value vs. Call by name  (0) 2019.04.23
Comments