0% found this document useful (0 votes)
7 views9 pages

Lazy List Implementation Overview

The document discusses various implementations of lazy lists in R. It begins with a simple implementation using promises and defines functions like Head and Tail to access the head and tail of a lazy list. It then explores alternate implementations including fully lazy versions, versions using delays, removing promises with assignment, and an implementation without promises. The document provides examples of constructing lists, selecting parts of lists, mapping and filtering lists, and interleaving lists. It gives classical examples like generating the Fibonacci sequence and finding prime numbers. It concludes with some discussion points on lazy list utility functions and optimizations.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views9 pages

Lazy List Implementation Overview

The document discusses various implementations of lazy lists in R. It begins with a simple implementation using promises and defines functions like Head and Tail to access the head and tail of a lazy list. It then explores alternate implementations including fully lazy versions, versions using delays, removing promises with assignment, and an implementation without promises. The document provides examples of constructing lists, selecting parts of lists, mapping and filtering lists, and interleaving lists. It gives classical examples like generating the Fibonacci sequence and finding prime numbers. It concludes with some discussion points on lazy list utility functions and optimizations.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

February 3, 2004

[Link]

1
1.1

Lazy List Implementation


A Simple Implementation

lazylist.R Cons <- function(head, tail) structure(list(head = head, tail = function() tail), class = "LazyList") Head <- function(x) x$head Tail <- function(x) x$tail() Is it worth assigning the tail to clear the promise? Use something like tail function with assignment tail = function() { tail <<- tail; tail } lazylist.R + [Link] <- function(x, ...) { cat(paste("<", Head(x), ", ... >\n")) }

1.2
1.2.1

Alternate Implementations
Fully Lazy Version

Version with lazy head. Seems to leak too much memory with nested promises. version with lazy head Cons <- function(head, tail) structure(list(head = function() head, tail = function() tail), class = "LazyList") Head <- function(x) x$head() [Link] <- function(x, ...) { cat("<lazy list>\n") } 1.2.2 Version Using Delay

Version using delaynot noticeably better for speed and less clear I think. version using delay Cons <- function(head, tail) structure(list(head = head, tail = delay(tail, environment())), class = "LazyList") Tail <- function(x) { d<-x$tail; d }

February 3, 2004

[Link]

1.2.3

Using Assignment To Remove Promise

Use assignment to eliminate the evaluated promise to avoid saving environments and nested promises. Could be done more eciently with internal code. version using assignment to remove promises Cons <- function(head, tail) { head <- head structure(list(head = head, tail = function() { tail <<- tail; tail }), class = "LazyList") } 1.2.4 Implementation Without Promises

Jazz up to handle errors in force nicely? version without promises Cons <- function(head, tail) { head <- head expr <- substitute(tail) prenv <- [Link]() env <- [Link](parent = NULL) assign("expr", expr, env = env) assign("prenv", prenv, env = env) structure(list(head = head, tail = env), class = "LazyList") } Tail <- function(x) { if (! exists("value", env = x$tail)) { expr <- get("expr", env = x$tail) prenv <- get("prenv", env = x$tail) assign("prenv", NULL, env = x$tail) assign("value", eval(expr, prenv), env = x$tail) } get("value", env = x$tail) }

1.3

Issues

Could use internal version that uses promises and removes them when evaluating. If an error occurs when forcing a promise then the evaluation pending marker remains set. In internal version could avoid this. (Or we could just use a try and some internal code for promise manipulation.)

February 3, 2004

[Link]

Lazy List Utility Functions

Mostly based on Paulsens ML book; some from Abelson and Sussman.

2.1

Constructing Lists

lazylist.R + intList <- function(i) Cons(i, intList(i+1)) Iterates <- function(x, f) { iter <- function(x, f) { y <- f(x) Cons(y, iter(y, f)) } Cons(x, iter(x, f)) } #**** [Link] FromList <- function(x) { v <- NULL; for (i in rev([Link](x))) v <- [Link]("Cons", list(i, v)) v } #**** fix Take for finite list Append <- function(x, y) { #**** coerce t list?? if ([Link](x)) y else #**** force eval of y to avoid buildup of nested promises? Cons(Head(x), Append(Tail(x), y)) } Repeat <- function(x) Append(x, Repeat(x))

February 3, 2004

[Link]

2.2

Selecting Parts of a List

lazylist.R + Elt <- function(x, n) { if (n <= 0) NULL else { while (n > 1 && ! [Link](x)) { n <- n - 1 x <- Tail(x) } if ([Link](x)) NULL else Head(x) } } Take <- function(n, x) { if (n <= 0) NULL else sapply(1:n, function(i) { v <- Head(x); x <<- Tail(x); v }) } Drop <- function(n, x) { if (n > 0) for (i in 1:n) x <- Tail(x) x }

February 3, 2004

[Link]

2.3

Mapping and Filtering

lazylist.R + TakeWhile <- function(test, x) { y <- x n <- 0 while (! [Link](x) && test(Head(x))) { n <- n + 1 x <- Tail(x) } Take(n, y) } DropWhile <- function(test, x) { while (! [Link](x) && test(Head(x))) x <- Tail(x) x } Filter <- function(x, test) { if (test(Head(x))) Cons(Head(x), Filter(Tail(x), test)) else Filter(Tail(x), test) } Filter <- function(x, test) { while (! test(Head(x))) x <- Tail(x) Cons(Head(x), Filter(Tail(x), test)) } Filter <- function(x, test) { while (! [Link](x) && ! test(Head(x))) x <- Tail(x) if ([Link](x)) NULL else Cons(Head(x), Filter(Tail(x), test)) } Map <- function(x, fun) { if ([Link](x)) NULL else Cons(fun(Head(x)), Map(Tail(x), fun)) }

February 3, 2004

[Link]

2.4

Interleaving Lists

lazylist.R + Interleave <- function(x, y) { if ([Link](x)) y else if ([Link](y)) x else Cons(Head(x), Interleave(y, Tail(x))) } Zip <- function(x, y) { if ([Link](x) || [Link](y)) NULL else Cons(Head(x), Cons(Head(y), Zip(Tail(x), Tail(y)))) }

3
3.1

Examples
Simple Examples

R session > intList(3) <lazy list> > i3<-intList(3) > Head(i3) [1] 3 > Head(Tail(i3)) [1] 4 > Head(Tail(Tail(i3))) [1] 5

3.2
3.2.1

Classical Examples
Fibonacci Sequence

bonacci sequence fib <- function(x,y) Cons(x, Cons(y, Tail(fib(y, x+y)))) fib1 <- function(x,y) Cons(x, fib1(y, x+y))

February 3, 2004

[Link]

Abelson and Sussman version: bonacci sequence + Add <- function(x,y) Cons(Head(x) + Head(y), Add(Tail(x), Tail(y))) fibs <- Cons(0, Cons( 1, Add(Tail(fibs), fibs))) Dening b naturally would need +.LaxyList method bonacci sequence + fibs <- Cons(0, Cons( 1, Tail(fibs) + fibs)) 3.2.2 Finding Primes

Abelson and Sussman version: primes Sieve <- function(x) { p <- Head(x) Cons(p, Sieve(Filter(Tail(x), function(y) y %% p != 0))) } p<-Sieve(intList(2)) Take(20, p) Blows up with too deep recursion much a R session + > options(expressions=2000) > p<-Sieve(intList(2)) > Take(97,p) # 98 fails Paulson version: primes + Sift <- function(x, p) Filter(x, function(y) y %% p != 0) Sieve <- function(x) { p <- Head(x) Cons(p, Sieve(Sift(Tail(x), p))) } Sieve <- function(x) Cons(Head(x), Sieve(Sift(Tail(x), Head(x))))

February 3, 2004

[Link]

Alternate version from Abelson and Sussman: primes + #***Higher order function to simplify this? isPrime <- function(x) { for (p in TakeWhile(function(p) p^2 <= x, primes)) if (x %% p == 0) return(FALSE) TRUE } primes <- Cons(2, Filter(intList(3), isPrime)) isPrime <- function(x) { p <- primes while (Head(p)^2 <= x) { if (x %% Head(p) == 0) return(FALSE) else p <- Tail(p) } TRUE }

3.3

More Statistical Examples

Richardson extrapolation; Aitken extrapolation; Newtons method for Gamma, say, with dierent convergence rules; Monte Carlo sequence (drop rst n, keep every m-th);

3.4

Miscellaneous Stu

This seems OK tests i <- intList(1) gc() # clear out .[Link] while (TRUE) i <- Tail(i) def tests + f <- function() { i <- intList(1) while (TRUE) i <- Tail(i) }

February 3, 2004

[Link]

Look at GC triggering again some time is missing arg in methods probably shouldnt exist make isMissing in envir.c public? Think about separating missing/substitute stu so it doesnt need to look at promises. Missing/substitute stu can be determined from the matched call. Matched calls can be computed at compile time in some settings; in others they can be computed lazily if they are not needed anyway. Look at CL Series and Gatherers package. Waters papers Look ad Gatherers in Python (with and without Stackless). [Link] [Link] Think about Iterators (eg CLU). Does Python list comprehension stu have anything to do with this?

You might also like