# Lecture 019

## Lazy Evaluation / Streams

Demand driven computation suspension: stop before next request laziness: can do more work if exposed multiple times, but memorlization can solve the issue

## Infinite Data Structure

signature STREAM =
sig
type 'a stream
datatype 'a front = Empty | Cons of 'a * 'a stream
val expose: 'a stream -> 'a front
val delay: (unit -> 'a front) -> 'a stream
val empty: 'a stream
val cons: 'a * 'a stream -> 'a stream
val null: 'a stream -> bool
val map: ('a * 'b) -> 'a stream -> 'b stream
val filter: ('a -> bool) -> 'a stream -> 'a stream
val take: 'a stream * int -> 'a list
end

structure Stream :> STREAM =
struct
datatype 'a stream = STREAM of unit -> 'a front
and 'a front = EMPTY | Con of 'a * 'a stream
val empty = STREAM (fn () => Empty)
fun expose (STREAM d) = d ()
fun delay d = STREAM d
fun cons (x, rest) = STREAM (fn () => Cons(x, rest))
fun null s = (case expose s of Empty => true | Cons _ => false)
(* This will do a lot of work because expose calls the stream *)

val natureNumber : int Stream.stream = ...
val negativeNumber = Stream.filter (fn n => n < 0) natureNumber
(*negativeNumber is empty, not button, but takes forever to evaluate null because filter happens when we try to see if there is an element*)

fun map' f Empty = Empty
| map' f (Cons(x, s)) = cons (f x, map f s)
and map f s = delay (fn () => map' f (expose s))

fun filter p s = delay (fn () => filter' p (expose s))
and filter' p Empty = Empty
| filter' p (Cons(x, s)) = if p x then Cons(x, filter p s) else filter' p (expose s)

fun append (s1, s2) = delay (fn () => append' (expose s1, s2))
and append' (Empty, s2) = expose s2
| append' (Cons(x, s1), s2) = Cons(x, append (s1, s2))

end



Examples:

fun ones' () = Stream.cons (1, Stream.delay ones')
val ones = Stream.delay one'

fun natsfrom' n = Stream.cons(n, S.delay (fn () => natsfrom' (n+1)))
fun natsfrom n = Stream.delay(fn () => natsfrom' n)
val nats = natsfrom 0

or...

fun natsfrom' n = Stream.cons(n, natsfrom (n+1))
and natsfrom n = Stream.delay (fn () => natsfrom 'n)
val nats = natsfrom 0
val Stream.Con(x0, r) = expose nats [0/x0, -/r]


Example of finding primes:

(*whether q is divisable by p*)
fun notdiv p q = q mod p <> 0
fun sieve s = Stream.delay (fn () -> sieve' (Stream.expose s))
and sieve' Stream.Empty = Stream.Empty
| sieve' (Stream.Cons(p, s)) = Stream.cons(p, sieve (Stream.filter(notdiv p) s))

val primes = sieve (natsfrom 2)


Table of Content