CSCI 2041

ADVANCED PROGRAMMING PRINCIPLES

Lazy Evaluation:

stream

Last time: manipulating infinite data structures in lazyCaml

let rec nats n = n::(nats (n+1))
let rec trues = true::trues

One way to implement these in OCaml is with a stream type, in which the tail of a stream is placed in a lambda expression to prevent eager evaluation:

type 'a stream = End | Cons of 'a * (unit -> 'a stream)
type 'a stream  = End | Cons of 'a * (unit -> 'a stream)

Let’s write hd_s, tl_s, take_s, nat_s, squares_s, map_s

let hd_s = function Cons(h,t) -> h | End -> failwith "hd_s"
let tl_s = function Cons(h,t) -> t () | End -> failwith "tl_s"
let rec take_s n s = match (n,s) with
| (0,_) | (_,End) -> []
| (_,Cons(h,t)) -> h::(take_s (n-1) (t ()))
let rec nats_s n = Cons (n, fun () -> nats_s (n+1))
let rec squares n = Cons (n*n, fun () -> squares (n+1))
let rec map_s f s = match s with
| Cons (h,t) -> Cons (f h, fun () -> map_s f (t ()))
| End -> End
let rec filter_s (p : 'a -> bool) (s : 'a stream) =
match s with End -> End
| Cons(h,t) -> if (p h) then Cons(h, fun () -> filter_s p (t ()))
  else filter_s p (t ())
let rec sieve p =
  Cons(p, fun () ->
          filter_s (fun a -> a mod p <> 0) (sieve (p+1)))
let rec merge (s1 : 'a stream) (s2 : 'a stream) =
  match (s1,s2) with
  | (End, _) -> s2
  | (_, End) -> s1
  | (Cons (h,t),_) -> Cons (h, fun () -> merge s2 (t ()))
let rec bstrs s = Cons(s, fun () -> merge (bstrs ("0"^s)) (bstrs ("1"^s)))

Technically, streams simulate normal order evaluation (call-by-name) but not lazy evaluation, since there is no sharing…

let rec natp n =
  let _ = Printf.printf "evaluated natp %d\n" n in
  Cons(n, fun () -> natp (n+1))

let double s = merge s s

take_s 10 (double (natp 0))

cs2041.org

// reveal.js plugins