-
Notifications
You must be signed in to change notification settings - Fork 1
/
lazy0.erl
141 lines (99 loc) · 3.15 KB
/
lazy0.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
-module(lazy0).
-compile([export_all]).
% THIS IS REPLACED IN lazy.erl BY A NAMED TABLE: NO NEED TO PASS IT IN EXPLICITLY.
% To use, need an ETS table. This does the trick; call thus:
% Tab = lazy:setup().
% Tab needs to be passed as a parameter to all functions;
% could alternatively do with
setup() ->
Tab = ets:new(foo,[]),
ets:insert(Tab,{0,1}),
Tab.
% Macro for constructing a new cell.
-define(cons(X,Xs,Tab), begin ets:insert(Tab,{0,next_ref(Tab)+1}) ,
ets:insert(Tab, {next_ref(Tab), {thunk, fun () -> {X,Xs} end}}),
% io:format("done cons insert~n"),
{ref,next_ref(Tab)} end).
% Get the next free cell, assuming that value stored in location 0
% keeps the locations used so far.
next_ref(Tab) ->
[{0,Ref}]=ets:lookup(Tab,0),
Ref.
nil() -> {}.
% Head of a stream.
head({ref,Ref},Tab) ->
% io:format("entered head~n"),
case ets:lookup(Tab,Ref) of
[{Ref,{thunk,F}}] -> Val = F(),
ets:insert(Tab,{Ref,Val}),
{H,_} = Val,
H;
[{Ref,{H,_}}] -> % io:format("head success~n"),
H
end.
% Tail of a stream.
tail({ref,Ref},Tab) ->
% io:format("entered tail~n"),
case ets:lookup(Tab,Ref) of
[{Ref,{thunk,F}}] -> Val = F(),
ets:insert(Tab,{Ref,Val}),
{_,T} = Val,
T;
[{Ref,{_,T}}] -> % io:format("tail success~n"),
T
end.
% Infinite stream of ones.
ones(Tab) ->
?cons(1,ones(Tab),Tab).
% Circular representation of the infinite stream of ones.
onesC(Tab) ->
This = next_ref(Tab)+1,
?cons(1,{ref,This},Tab).
% Infinite stream of n, n+1, … .
ns(N,Tab) ->
?cons(N,ns(N+1,Tab),Tab).
% Infinite stream of primes, using a sieve algorithm.
primes(Tab) -> sieve(ns(2,Tab),Tab).
% The top-level sieve function: workhorse of primes/1.
sieve(Ns,Tab) ->
H = head(Ns,Tab),
?cons(H,sieve(cull(H,tail(Ns,Tab),Tab),Tab),Tab).
% Remove all the multiples of N from the stream Ns.
cull(N,Ns,Tab) ->
H = head(Ns,Tab),
case H rem N of
0 -> cull(N,tail(Ns,Tab),Tab);
_ -> ?cons(H,cull(N,tail(Ns,Tab),Tab),Tab)
end.
% Get the Nth element of a stream.
index(N,Ls,Tab) ->
case N of
0 -> head(Ls,Tab);
_ -> index(N-1,tail(Ls,Tab),Tab)
end.
% Zip together two streams of numbers with +.
addZip(Xs,Ys,Tab) ->
?cons(head(Xs,Tab)+head(Ys,Tab), addZip(tail(Xs,Tab),tail(Ys,Tab),Tab),Tab).
% The infinite stream of fibs.
fibs(Tab) ->
?cons(0,
?cons(1,
addZip(fibs(Tab),tail(fibs(Tab),Tab),Tab),Tab),Tab).
% Circular representation of the infinite stream of fibs.
fibsC(Tab) ->
This = next_ref(Tab)+1,
Next = This+1,
?cons(0,
?cons(1,
addZip({ref,This},{ref,Next},Tab),Tab),Tab).
% Circular representation of the infinite stream of fibs (variant).
fibsCVar(Tab) ->
This = next_ref(Tab)+1,
?cons(0,
?cons(1,
addZip({ref,This},tail({ref,This},Tab),Tab),Tab),Tab).
% Print the first N values of a stream, one per line.
ps(_Xs,0,_T) -> ok;
ps(Xs,N,Tab) ->
io:format("~w~n",[head(Xs,Tab)]),
ps(tail(Xs,Tab),N-1,Tab).