{
lazy list class
}
include "std.led";
class LazyList [X : equality];
var
isEmpty : boolean;
headFun : function()->X;
tailFun : function()->LazyList[X];
headDefined : boolean;
tailDefined : boolean;
function empty()->boolean;
begin
return isEmpty;
end;
function head()->X;
var
hd : X;
begin
hd := headFun();
if ~ headDefined then begin
headDefined := true;
headFun := function()->X;
begin
return hd;
end;
end;
return hd;
end;
function tail()->LazyList[X];
var
tl : LazyList[X];
begin
tl := tailFun();
if ~ tailDefined then begin
tailDefined := true;
tailFun := function()->LazyList[X];
begin
return tl;
end;
end;
return tl;
end;
end;
function emptyList [X : equality] ()->LazyList[X];
begin
return LazyList[X](
true, NIL, NIL, false, false);
end;
function cons [X : equality]
(byName hd : X, byName tl : LazyList[X])->LazyList[X];
begin
return LazyList[X](
false,
function()->X; begin return hd; end,
function()->LazyList[X]; begin return tl; end,
false, false);
end;
function map [X, Y : equality]
(transform : function(X)->Y, data : LazyList[X])->LazyList[Y];
begin
if data.empty() then
return emptyList[Y]()
else
return cons[Y](transform(data.head()),
map[X, Y](transform, data.tail()));
end;
function printFirstN [X : equality](aList : LazyList[X], n : integer);
var
i : integer;
theList : LazyList[X];
begin
theList := aList;
for i := 1 to n do
if ~ theList.empty() then begin
print(theList.head());
print(" ");
theList := theList.tail();
end;
print("\n");
end;
function iToj(i, j : integer)->LazyList[integer];
begin
if i <= j then
return cons[integer](i, iToj(i+1, j))
else
return emptyList[integer]();
end;
function oneToN(n : integer)->LazyList[integer];
begin
return iToj(1, n);
end;
function reduce [X : equality, Y : object] (aList : LazyList[X], ident : Y,
binFun: function(X, Y)->Y )->Y;
begin
if aList.empty() then
return ident
else
return binFun(aList.head(),
reduce[X, Y](aList.tail(), ident, binFun));
end;
function count [X : equality]
(theList : LazyList[X], pred : function(X)->boolean)->integer;
begin
return reduce[X, integer]
(theList,
0,
function (ele : X, soFar : integer)->integer;
begin
if pred(ele) then
return soFar + 1;
return soFar;
end);
end;
function isPrime(N : integer)->integer;
begin
if 2 >= count[integer]
(map[integer, integer](N.remainder, oneToN(N)), 0.equals)
then
return N
else
return 0;
end;
function filter [X : equality]
(aList : LazyList[X], pred : function(X)->boolean)->LazyList[X];
begin
if aList.empty() then
return aList;
if pred(aList.head()) then
return cons[X](aList.head(), filter[X](aList.tail(), pred))
else
return filter[X](aList.tail(), pred);
end;
function sieve(aList : LazyList[integer])->LazyList[integer];
const
n := aList.head();
function divides(x : integer)->boolean;
begin
return 0 <> x % n;
end;
begin
return cons[integer](n, sieve(filter[integer](aList.tail(), divides)));
end;
function expansion [X : equality]
(start : X, next : function(X)->X)->LazyList[X];
begin
return cons[X](start, expansion[X](next(start), next));
end;
function abs (n : real)->real;
begin
if n < 0.0 then
return - n;
return n;
end;
function converge (terms : LazyList[real], epsilon : real)->real;
var
a, b : real;
begin
a := terms.head();
terms := terms.tail();
b := terms.head();
while abs(a - b) > epsilon do begin
a := b;
terms := terms.tail();
b := terms.head();
end;
return b;
end;
function sqrt (n : real)->real;
function nextTerm(x : real)->real;
begin
return (x + n / x) / 2.0;
end;
begin
return converge(expansion[real](n, nextTerm), 0.02);
end;
function cubeRoot (n : real)->real;
function nextTerm(x : real)->real;
begin
return (x + n / (x * x)) / 2.0;
end;
begin
return converge(expansion[real](n, nextTerm), 0.02);
end;
function fibFrom (current : integer, next : function(integer)->integer)
->LazyList[integer];
const
nextVal := next(current);
begin
return cons[integer](nextVal, fibFrom(nextVal, current.plus));
end;
function merge[X : ordered] (first, second : LazyList[X])->LazyList[X];
begin
if first.empty() then
return second;
if second.empty() then
return first;
while first.head() = second.head() do begin
first := first.tail();
if first.empty() then
return second;
end;
if first.head() < second.head() then
return cons[X](first.head(), merge[X](first.tail(), second))
else
return cons[X](second.head(), merge[X](first, second.tail()));
end;
var
integers : LazyList[integer];
evens : LazyList[integer];
primes : LazyList[integer];
primes2 : LazyList[integer];
odds : LazyList[integer];
fibs : LazyList[integer];
function hamming(data : LazyList[integer])->LazyList[integer];
const
n := data.head();
begin
return cons[integer](n,
hamming(
merge[integer](data.tail(),
cons[integer](2 * n,
cons[integer](3 * n,
cons[integer](5 * n,
emptyList[integer]()))))));
end;
begin
{ integers := cons[integer](1, map[integer, integer](1.plus, integers));
printFirstN[integer] (integers, 26);
evens := map[integer, integer](2.times, integers);
printFirstN[integer] (evens, 6);
primes := filter[integer](map[integer, integer](isPrime, integers),
0.notEquals);
printFirstN[integer](primes, 10);
primes2 := sieve(integers.tail());
printFirstN[integer](primes2, 10);
odds := expansion[integer](1, 2.plus);
printFirstN[integer](odds, 10);
print("sqrt of 101.5 is " + sqrt(101.5) + "\n");
print("cuberoot of 126.5 is " + cubeRoot(126.5) + "\n");
fibs := fibFrom(0, 1.plus);
printFirstN[integer](fibs, 5);}
printFirstN[integer]
(hamming(cons[integer](1, emptyList[integer]())), 100);
end;