Lazy Evaluation em Scala

Post on 09-Jul-2015

618 views 2 download

description

Presented at: TDC 2012, July/2012.

Transcript of Lazy Evaluation em Scala

LAZY EVALUATIONEM SCALA

Pedro Matiellopmatiello@gmail.com

@pmatiello

LAZY EVALUATIONEM SCALA

SCALA

•Tipagem estática

•Programação orientada a objetos

•Programação funcional

PROGRAMAÇÃO FUNCIONAL

•A operação fundamental é a aplicação de funções

•Um programa é uma função

•Normalmente composta de outras funções

•A entrada são os argumentos

•A saída é o valor devolvido

��

��

��

f(x) = x²

•Transparência referencial (referential transparency)

•A aplicação de uma função não produz efeitos colaterais

•Funções de ordem superior (higher-order functions)

•Avaliação atrasada (lazy evaluation)

LAZY EVALUATION

•A avaliação da expressão é atrasada até que o valor seja necessário (non-strict evaluation)

•Avaliações repetidas são evitadas (sharing)

def condicao1 = { println("Avaliou condicao1"); true }def condicao2 = { println("Avaliou condicao2"); false }def condicao3 = { println("Avaliou condicao3"); true }

SHORT-CIRCUIT EVALUATION

def condicao1 = { println("Avaliou condicao1"); true }def condicao2 = { println("Avaliou condicao2"); false }def condicao3 = { println("Avaliou condicao3"); true }

scala> condicao1 && condicao1 && condicao2 && condicao3

SHORT-CIRCUIT EVALUATION

def condicao1 = { println("Avaliou condicao1"); true }def condicao2 = { println("Avaliou condicao2"); false }def condicao3 = { println("Avaliou condicao3"); true }

scala> condicao1 && condicao1 && condicao2 && condicao3Avaliou condicao1Avaliou condicao1Avaliou condicao2res0: Boolean = false

SHORT-CIRCUIT EVALUATION

def condicao1 = { println("Avaliou condicao1"); true }def condicao2 = { println("Avaliou condicao2"); false }def condicao3 = { println("Avaliou condicao3"); true }

scala> condicao1 && condicao1 && condicao2 && condicao3Avaliou condicao1Avaliou condicao1Avaliou condicao2res0: Boolean = false

SHORT-CIRCUIT EVALUATION

(não é lazy evaluation)

def loop(condicao: => Boolean)(expressao: => Unit) { if (condicao) { expressao loop(condicao)(expressao) }}

CALL BY NAME

def loop(condicao: => Boolean)(expressao: => Unit) { if (condicao) { expressao loop(condicao)(expressao) }}

CALL BY NAME

def loop(condicao: => Boolean)(expressao: => Unit) { if (condicao) { expressao loop(condicao)(expressao) }}

var i = 0;loop(i < 5) { println(i); i=i+1 }

CALL BY NAME

def loop(condicao: => Boolean)(expressao: => Unit) { if (condicao) { expressao loop(condicao)(expressao) }}

var i = 0;loop(i < 5) { println(i); i=i+1 }01234

CALL BY NAME

def loop(condicao: => Boolean)(expressao: => Unit) { if (condicao) { expressao loop(condicao)(expressao) }}

var i = 0;loop(i < 5) { println(i); i=i+1 }01234

CALL BY NAME

(apenas non-strict evaluation)

scala> lazy val x = { println("avaliou x"); "XXX" }x: java.lang.String = <lazy>

scala> lazy val y = { println("avaliou y"); "YYY" }y: java.lang.String = <lazy>

LAZY VALS

scala> lazy val x = { println("avaliou x"); "XXX" }x: java.lang.String = <lazy>

scala> lazy val y = { println("avaliou y"); "YYY" }y: java.lang.String = <lazy>

LAZY VALS

scala> lazy val x = { println("avaliou x"); "XXX" }x: java.lang.String = <lazy>

scala> lazy val y = { println("avaliou y"); "YYY" }y: java.lang.String = <lazy>

scala> if (true) x else y

LAZY VALS

scala> lazy val x = { println("avaliou x"); "XXX" }x: java.lang.String = <lazy>

scala> lazy val y = { println("avaliou y"); "YYY" }y: java.lang.String = <lazy>

scala> if (true) x else yavaliou xres0: java.lang.String = XXX

LAZY VALS

scala> lazy val x = { println("avaliou x"); "XXX" }x: java.lang.String = <lazy>

scala> lazy val y = { println("avaliou y"); "YYY" }y: java.lang.String = <lazy>

scala> if (true) x else yavaliou xres0: java.lang.String = XXX

scala> if (true) x else y

LAZY VALS

scala> lazy val x = { println("avaliou x"); "XXX" }x: java.lang.String = <lazy>

scala> lazy val y = { println("avaliou y"); "YYY" }y: java.lang.String = <lazy>

scala> if (true) x else yavaliou xres0: java.lang.String = XXX

scala> if (true) x else yres1: java.lang.String = XXX

LAZY VALS

scala> lazy val naturais:List[Int] =0 :: naturais.map(_+1)

naturais: List[Int] = <lazy>

STREAMS

scala> lazy val naturais:List[Int] =0 :: naturais.map(_+1)

naturais: List[Int] = <lazy>

STREAMS

� QDWXUDLV�PDS�B���

QDWXUDLV�

QDWXUDLV�

����

scala> lazy val naturais:List[Int] =0 :: naturais.map(_+1)

naturais: List[Int] = <lazy>

STREAMS

QDWXUDLV�

���� �

scala> lazy val naturais:List[Int] =0 :: naturais.map(_+1)

naturais: List[Int] = <lazy>

STREAMS

QDWXUDLV�

���� � �

scala> lazy val naturais:List[Int] =0 :: naturais.map(_+1)

naturais: List[Int] = <lazy>

STREAMS

scala> lazy val naturais:List[Int] =0 :: naturais.map(_+1)

naturais: List[Int] = <lazy>

scala> naturais.take(20)

STREAMS

scala> lazy val naturais:List[Int] =0 :: naturais.map(_+1)

naturais: List[Int] = <lazy>

scala> naturais.take(20)java.lang.StackOverflowError! at .naturais(<console>:7)! at .naturais(<console>:7)! ...

STREAMS

scala> lazy val naturais:Stream[Int] =0 #:: naturais.map(_+1)

naturais: Stream[Int] = <lazy>

STREAMS

scala> lazy val naturais:Stream[Int] =0 #:: naturais.map(_+1)

naturais: Stream[Int] = <lazy>

scala> naturais.take(20)

STREAMS

scala> lazy val naturais:Stream[Int] =0 #:: naturais.map(_+1)

naturais: Stream[Int] = <lazy>

scala> naturais.take(20)res0: scala.collection.immutable.Stream[Int] = Stream(0, ?)

STREAMS

scala> lazy val naturais:Stream[Int] =0 #:: naturais.map(_+1)

naturais: Stream[Int] = <lazy>

scala> naturais.take(20).toListres1: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

STREAMS

CONTUDO, PORÉM, TODAVIA

•A Lazy Evaluation e a Eager Evaluation podem produzir resultados diferentes

1 var y = 22 val x = y3 y = 34 println("x = " + x)

EAGER

1 var y = 22 val x = y3 y = 34 println("x = " + x)

y=2

EAGER

1 var y = 22 val x = y3 y = 34 println("x = " + x)

y=2, x=2

EAGER

1 var y = 22 val x = y3 y = 34 println("x = " + x)

y=3, x=2

EAGER

1 var y = 22 val x = y3 y = 34 println("x = " + x)

x = 2

y=3, x=2

EAGER

1 var y = 22 lazy val x = y3 y = 34 println("x = " + x)

LAZY

1 var y = 22 lazy val x = y3 y = 34 println("x = " + x)

y=2

LAZY

1 var y = 22 lazy val x = y3 y = 34 println("x = " + x)

y=2, x=y

LAZY

1 var y = 22 lazy val x = y3 y = 34 println("x = " + x)

y=3, x=y

LAZY

1 var y = 22 lazy val x = y3 y = 34 println("x = " + x)

x = 3

y=3, x=3

LAZY

•O sharing do resultado das expressões pode elevar o consumo de memória

scala> lazy val naturais:Stream[Int] =0 #:: naturais.map(_+1)

naturais: Stream[Int] = <lazy>

SHARING

scala> lazy val naturais:Stream[Int] =0 #:: naturais.map(_+1)

naturais: Stream[Int] = <lazy>

scala> naturais.foreach{ x:Int => }

SHARING

scala> lazy val naturais:Stream[Int] =0 #:: naturais.map(_+1)

naturais: Stream[Int] = <lazy>

scala> naturais.foreach{ x:Int => }Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

SHARING

scala> lazy val naturais:Stream[Int] =0 #:: naturais.map(_+1)

naturais: Stream[Int] = <lazy>

scala> naturais.foreach{ x:Int => }Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

SHARING

•Erros podem aparecer em locais diferentes do código

1 val x = { throw new RuntimeException; 5 }2 println("x + 3 =")3 println(x+3)

EAGER

1 val x = { throw new RuntimeException; 5 }2 println("x + 3 =")3 println(x+3)

Exception in thread "main" java.lang.RuntimeException! at Test$.main(Test.scala:1)! at Test.main(Test.scala)

EAGER

1 val x = { throw new RuntimeException; 5 }2 println("x + 3 =")3 println(x+3)

Exception in thread "main" java.lang.RuntimeException! at Test$.main(Test.scala:1)! at Test.main(Test.scala)

EAGER

1 lazy val x = { throw new RuntimeException; 5 }2 println("x + 3 =")3 println(x+3)

LAZY

1 lazy val x = { throw new RuntimeException; 5 }2 println("x + 3 =")3 println(x+3)

LAZY

1 lazy val x = { throw new RuntimeException; 5 }2 println("x + 3 =")3 println(x+3)

x + 3 =

LAZY

1 lazy val x = { throw new RuntimeException; 5 }2 println("x + 3 =")3 println(x+3)

x + 3 =Exception in thread "main" java.lang.RuntimeException! at Test$.main(Test.scala:1)! at Test$.main(Test.scala:3)! at Test.main(Test.scala)

LAZY

1 lazy val x = { throw new RuntimeException; 5 }2 println("x + 3 =")3 println(x+3)

x + 3 =Exception in thread "main" java.lang.RuntimeException! at Test$.main(Test.scala:1)! at Test$.main(Test.scala:3)! at Test.main(Test.scala)

LAZY

LAZY EVALUATION EM SCALA

Pedro Matiellopmatiello@gmail.com

@pmatiello