Lecture 23
Stephen Brookes
today
lazy functional programming
being lazy
Defer computation until its result is needed
call-by-value
(* repeat : a list -> a list *)!
fun repeat L = L @ repeat L
lazy lists
a thunk
datatype a lazylist = !
Cons of a * (unit -> a lazylist)
Zeros
(* zeros : unit -> int lazylist *)!
fun zeros ( ) = Cons(0, zeros)!
!
Ones
(* ones : unit -> int lazylist *)!
fun ones ( ) = Cons(1, ones)!
!
Nats
(* nats : int -> (unit -> int lazylist) *)!
fun nats n ( ) = Cons(n, nats (n+1))!
!
0,1,2,3,4,...
2,3,4,5,6,...
mklazy
(* mklazy : int list -> int lazylist *)!
!
representation
A t lazylist value represents a sequence of values of type t
Zeros
Ones
nats 42 ( )
mklazy [1,2,3]
represents 0,0,0,0,
represents 1,1,1,1,
represents 42,43,44,45,
represents 1,2,3,0,0,0,
lazyappend
(* lazyappend : a list * (unit -> a lazylist) -> a lazylist *)!
!
fun lazyappend ([ ], h) = h( )!
| lazyappend (x::xs, h) = !
Cons(x, fn ( ) => lazyappend(xs, h))!
!
where
h1( ) =>* Cons(1, h2)
and
h2( ) =>* Cons(2, h3)
and so on
lazyappend
(* lazyappend : a list * (unit -> a lazylist) -> a lazylist *)!
!
fun lazyappend ([ ], h) = h( )!
| lazyappend (x::xs, h) = !
Cons(x, fn ( ) => lazyappend(xs, h))!
!
where
WRONG! Why?
lazyappend
If
h( ) !
represents y0,y1,y2,y3,
then !
lazyappend ([x0,,xk], h)!
represents x0,,xk,y0,y1,y2,y3,
repeat
(* repeat : a list -> a lazylist *)!
(* REQUIRES xs not the empty list *)!
(* ENSURES repeat(xs) terminates!
and represents lazy list consisting of
xs repeated over and over *)!
!
repeat [0]
repeat [0] =>* Cons(0, h0)
where h0( ) =>* Cons(0, h1))
and h1( ) =>* Cons(0, h2))
and so on
repeat [0] represents 0,0,0,0,0,...
show
(* show : int -> a lazylist -> a list *)!
fun show 0 _ = [ ]!
| show n (Cons(x, h)) = x :: show (n-1) (h( ))
lazy equality
Lazy list values A and B are equal
For all n 0,
show n A = show n B.
lazymap
(* lazymap : (a -> b) -> a lazylist -> b lazylist *)!
!
recursive call
is deferred
If f is total and L represents x0,x1,x2,
then lazymap f L represents f(x0),f(x1),f(x2),
lazymap fusion
If f : t
same
as
saying
lazyzip
(* lazyzip : a lazylist * b lazylist -> (a * b) lazylist
*)!
recursive call
is deferred
If
A represents a0,a1,a2,!
and B represents b0,b1,b2,!
then lazyzip(A,B) represents (a0,b0),(a1,b1),(a2,b2),!
lazy filter
(* lazyfilter : (a -> bool) -> a lazylist -> a lazylist *)!
!
warning
What happens when we evaluate
lazyfilter (fn x => x=0) (repeat [1])
specification
If p is total and L represents a0,a1,a2,!
and infinitely many ai satisfy p
then lazyfilter p L represents the sequence of !
all the ai satisfying p
lazy factorials
(* facts : unit -> int lazy list *)!
!
fun facts( ) = !
Cons(1, fn ( ) => !
lazymap (op * ) (lazyzip(facts( ), !
nats 2 ( )) ) )
Primes
(* sift : int -> int lazylist -> int lazylist *)!
fun sift x = lazyfilter (fn y => y mod x <> 0)!
!
prime
Then x is the
And sift x (h( )) consists of the integers 2
th
(n+1)