Evaluation strategies. Applications of lazy evaluation

Evaluation strategies. Applications of lazy
evaluation
Evaluation strategies. Applications of lazy evaluation
Purpose of this lecture
Clarify the following notions:
Evaluation strategies
applicative (or eager) evaluation versus lazy evaluation
H ASKELL versus R ACKET
Lazy evaluation in R ACKET
with functional closures
with promises
Applications: streams
Natural numbers
Fibonacci numbers
Prime numbers
Evaluation strategies. Applications of lazy evaluation
Evaluation strategies
1. Applicative (or eager) evaluation
Arguments are evaluated before being passed to function calls
Example
(λx.λy .(x + y ) 1 (λz.(z + 2) 3)) = (λx.λy .(x + y ) 1 5)
= λy .(1 + y ) 5
= 6.
Evaluation strategies. Applications of lazy evaluation
Evaluation strategies
1. Applicative (or eager) evaluation
Arguments are evaluated before being passed to function calls
Example
(λx.λy .(x + y ) 1 (λz.(z + 2) 3)) = (λx.λy .(x + y ) 1 5)
= λy .(1 + y ) 5
= 6.
Remarks
With this evaluation strategy, all function calls receive
values as arguments
Therefore, it is also known as call by value evaluation
R ACKET and all imperative languages perform applicative
evaluation of function calls.
Evaluation strategies. Applications of lazy evaluation
Evaluation strategies
Lazy evaluation
The evaluation of an expression is delayed until it is really
needed.
Example
(λx.λy .(x + y ) 1 (λz.(z + 2) 3)) = (λy .(1 + y ) (λz.(z + 2) 3)) =
1 + (λz.(z + 2) 3) = 1 + 5 = 6.
Evaluation strategies. Applications of lazy evaluation
Evaluation strategies
Lazy evaluation
The evaluation of an expression is delayed until it is really
needed.
Example
(λx.λy .(x + y ) 1 (λz.(z + 2) 3)) = (λy .(1 + y ) (λz.(z + 2) 3)) =
1 + (λz.(z + 2) 3) = 1 + 5 = 6.
Remarks
The function call (λz.(z + 2) 3) is sent as parameter, and
its evaluation is delayed until needed.
H ASKELL is a functional programming language with lazy
evaluation strategy.
Evaluation strategies. Applications of lazy evaluation
Eager versus Lazy evaluation
Which one is better?
Both have advantages and disadvantages.
Disadvantages of eager evaluation
B May perform some useless computations
B May run never-ending computations (see example)
Disadvantages of lazy evaluation:
B Some computations can be duplicated
Example
Let fix = λf .(f (fix f )) and ct = λx.1.
Eager evaluation of fix ct runs forever:
fix ct = ct (fix ct) = ct (ct (fix ct)) = . . .
Lazy evaluation of fix ct stops immediately:
fix ct = ct (fix ct) = 1
Evaluation strategies. Applications of lazy evaluation
Lazy evaluation in R ACKET
Although R ACKET has applicative evaluation strategy, we can
simulate lazy evaluation in two ways:
1
With nullary functional closures
A nullary functional closure is a created by a lambda
expression with zero arguments:
(lambda () body)
2
with delay/force promises
Evaluation strategies. Applications of lazy evaluation
Lazy evaluation with nullary functional closures
Main idea:
To define a function with lazy evaluation, wrap its body in
(lambda () ...)
Example (Lazy version of sum)
> (define sum
(lambda (x y)
(lambda ()
(+ x y))))
> (sum 1 2)
#<procedure>
>((sum 1 2))
3
R EMARK : (sum 1 2) returns a function that expects 0 input
arguments (that is, a nullary functional closure).
A nullary function call of f is (f).
Evaluation strategies. Applications of lazy evaluation
Lazy evaluation with delay/force
Example (delayed evaluation of sum)
The conventional definition of sum is:
> (define sum (lambda (x y) (+ x y)))
To delay it’s evaluation, call
> (define s (delay (sum 1 2)))
> s
#promise
To perform a delayed computation c, call (force c):
> (force s)
3
Evaluation strategies. Applications of lazy evaluation
Lazy evaluation with delay/force
Example (delayed version of sum)
> (define sum
(lambda (x y)
(delay (+ x y))))
> (sum 1 2)
#promise
> (force (sum 1 2))
3
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Streams
Stream: a finitely representation of an infinite list.
Examples of infinite lists that can be represented by streams:
All ones: (1 1 1 ...)
Natural numbers: (0 1 2 3 ...)
Fibonacci numbers: (1 1 2 3 5 8 13 ...)
(f0 = f1 = 1 fn+2 = fn + fn+1 for all n ≥ 0)
Prime numbers: (2 3 5 7 11 13 ...)
Main idea of stream representation
(a1 ... ak . gen)
where gen is a generator that can be used to generate the rest
of the stream. Typically, gen is either a nullary function or a
promise.
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of all ones
Implementation with nullary function as generator
> (define make-ones (lambda () (cons 1 make-ones)))
> (define all-ones (make-ones))
> ; extract list of first n elements from a stream
(define (take n stream)
(if (= n 0)
null
(if (pair? stream)
(cons (car stream)
(take (- n 1) (cdr stream)))
(take n (stream)))))
> (take 4 all-ones) ; test
’(1 1 1 1)
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of natural numbers starting from 0
Implementation with promises
; generator for natural numbers
(define make-naturals
(lambda (k)
(cons k (delay (make-naturals (+ k 1))))))
; stream of natural numbers starting from 0
(define all-naturals (make-naturals 0))
; extract first n elements from the stream
(define (take n stream)
(if (= n 0)
null
(if (pair? stream)
(cons (car stream)
(take (- n 1) (cdr stream)))
(take n (force stream)))))
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Streams
Remarks
The implementation details of a stream (with nullary functions, or
with delay/force) should be hidden to the user.
Exercise: Reimplement make-ones with delay/force, and
all-naturals with nullary functions.
Example: take that works on both kinds of implementation
(define (take n stream)
(if (= n 0)
null
(if (pair? stream)
(cons (car stream)
(take (- n 1) (cdr stream)))
(take n (if (promise? stream)
(force stream)
(stream))))))
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of Fibonacci numbers
Useful observation: the stream fib of Fibonacci numbers has
the following useful property:
fib + (cdr fib) yields (cdr (cdr fib))
fib = f0 f1 f2 . . . +
(cdr fib) = f1 f2 f3 . . .
f0 f1
f2 f3 f4 . . .
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of Fibonacci numbers
Useful observation: the stream fib of Fibonacci numbers has
the following useful property:
fib + (cdr fib) yields (cdr (cdr fib))
fib = f0 f1 f2 . . . +
(cdr fib) = f1 f2 f3 . . .
f0 f1
f2 f3 f4 . . .
Once we know the first two elements f0 and f1 , we can start
generating the rest of the stream:
fib = (1
1 . gen)
where the implementation of the generator gen implements
the addition of streams fib with (cdr fib).
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of Fibonacci numbers
(define fib
(cons 1 (cons 1 (delay (add fib (cdr fib))))))
; addition of two streams
(define (add s1 s2)
(if (promise? s1)
(add (force s1) s2)
(if (promise? s2)
(add s1 (force s2))
(cons (+ (car s1) (car s2))
(delay (add (cdr s1) (cdr s2)))))))
Test:
> (take 10 fib)
’(1 1 2 3 5 8 13 21 34 55)
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of prime numbers
Main idea: Erathostene’s sieve
Consider the stream all all natural numbers starting with 2:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of prime numbers
Main idea: Erathostene’s sieve
Consider the stream all all natural numbers starting with 2:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
Remove all elements divisible with the first element of the
stream, except the first element
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of prime numbers
Main idea: Erathostene’s sieve
Consider the stream all all natural numbers starting with 2:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
Remove all elements divisible with the first element of the
stream, except the first element
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
Repeat this process on the tail of what is left:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
etc.
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Useful operations: filter and map of streams
(myfilter pred stream) returns the stream of elements from
stream for which pred holds.
(mymap f stream) applies unary function f to all elements of
stream
(define myfilter (lambda (p s)
(if (promise? s)
(myfilter p (force s))
(if (p (car s))
(cons (car s) (delay (myfilter p (cdr s))))
(myfilter p (cdr s))))))
(define mymap (lambda (f s)
(if (promise? s)
(mymap f (force s))
(cons (f (car s)) (delay (mymap f (cdr s)))))))
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of prime numbers
; some auxiliary stuff
(define (divides? x y) (zero? (remainder x y)))
; Erathostenes’ sieve
(define (sieve s)
(if (promise? s)
(sieve (force s))
(cons (car s)
(delay (sieve
(myfilter
(lambda (x) (not (divides? x (car s))))
(cdr s)))))))
(define all-primes (sieve (make-naturals 2)))
Evaluation strategies. Applications of lazy evaluation
Applications of lazy evaluation
Stream of prime numbers
Tests
> ; first 10 prime numbers
(take 10 all-primes)
’(2 3 5 7 11 13 17 19 23 29)
> ; first prime greater than 200
(car (myfilter (lambda (x) (> x 200)) all-primes))
211
> ; first ten multiples of 5
(take 10
(mymap (lambda (x) (* 5 x)) all-naturals))
’(0 5 10 15 20 25 30 35 40 45)
> ; first ten elements of fib + all-primes
(take 10 (add fib all-primes))
’(3 4 7 10 16 21 30 40 57 84)
Evaluation strategies. Applications of lazy evaluation