-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrampoline.py
executable file
·238 lines (207 loc) · 4.71 KB
/
trampoline.py
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# A sort of tail-call "simulation" via a "trampolined" process?
# The while loop repeatedly invokes the closure, named ftrc,
# which is referenced by variable rv.
#
def ft(p1,p2):
pi1=p1; pi2=p2
#
def fti(p1,p2):
nonlocal pi1, pi2
print(pi1,pi2)
if (p2==4):
return None
pi1=p1+1; pi2=p2+2
return ftrc
# fti(p1+1,p2+2)
#
def ftrc():
return fti(pi1,pi2)
#
rv=ftrc
while(rv is not None):
rv=rv()
return pi1, pi2
def ftt(p1,p2):
"""
This is a function designed to be trampoline-able.
Returns a reference to a closure designed to be given
to the trampoline() function.
"""
pi1,pi2 = p1,p2
def fti(p1,p2):
nonlocal pi1,pi2
if(p2==4):
return p1,p2
pi1,pi2=p1+1,p2+2
return ftrc
#
def ftrc():
return fti(pi1,pi2)
#
# Return a reference to a closure which invokes
# the function-which-would-have-used-tail-recursion.
return ftrc
def trampoline(f):
"""
This is designed to be applied to a trampoline-able function.
"""
rv = f()
while(callable(rv)):
rv=rv()
return rv
# So, an example of invoking the above would be:
# trampoline(ftt(0,-1982))
# which returns:
# (994, 4)
# whereas the recursive version,
# ftcr(0,-1982)
# would blow up Python's call stack...
## def ftc(p1p,p2p):
## pi1=p1+1; pi2=p2+2
## return fti(pi1,pi2)
"""
So,
we'd like a decorator to take away some of the syntactical pain.
So that:
@trampoline2
def ft(p1,p2) ....
would be nice.
What about
"""
def trampolinized(f):
# fi = f()
#
print("Trampolinization taking place!")
print("Trampolinifiying function: ", f.__name__)
def innerTrampoline():
# r = fi()
r = f()
while(callable(r)):
r = r()
return r
#
return innerTrampoline
def ftt1(p1,p2):
pi1,pi2 = p1,p2
#
def fti(p1,p2):
nonlocal pi1,pi2
if(p2==4):
return p1,p2
pi1,pi2=p1+1,p2+2
return ftrc
def ftrc():
return fti(pi1,pi2)
return trampolinized(ftrc)
# def trampolinify(f):
def ftt2(p1,p2):
pi1,pi2 = p1,p2
#
def fti(p1,p2):
nonlocal pi1,pi2
if(p2==4):
return p1,p2
pi1,pi2=p1+1,p2+2
return ftrc
#
def ftrc():
return fti(pi1,pi2)
#
# This shows how there is potential to use a decorator in order
# to "trampoline-ize" this "tail-recursive" process, in a
# rather general fashion:
@trampolinized
def fi():
return ftrc
#
return fi()
def ftt3(p1,p2):
pi1,pi2 = p1,p2
#
def fti(p1,p2):
nonlocal pi1,pi2
if(p2==4):
return p1,p2
pi1,pi2=p1+1,p2+2
return ftrc
#
def ftrc():
return fti(pi1,pi2)
#
return trampolinized(ftrc)()
def ftt4(p1,p2):
pi1,pi2 = p1,p2
#
def fti(p1,p2):
nonlocal pi1,pi2
if(p2==4):
return p1,p2
pi1,pi2=p1+1,p2+2
return ftrc
#
@trampolinized
def ftrc():
return fti(pi1,pi2)
#
return ftrc()
def trampoline2(f):
fi = f()
#
def innerTrampoline():
r = fi()
while(callable(r)):
r = r()
return r
#
return innerTrampoline
##f1 = ftt(0,1982)
##@trampoline
##def fttid():
## return f1
##@trampoline2
##def ftt1o(p1,p2):
## return ftt(p1,p2)
##
##@trampoline2
##def ftt1o1(**kwargs):
## pi1=kwargs['p1']; pi2=kwargs['p2']
## #
## def fti(p1,p2):
## nonlocal pi1, pi2
## if(p2==4):
## return p1,p2
## pi1,pi2=p1+1,p2+2
## return ftrc
## #
## def ftrc():
## return fti(pi1,pi2)
## #
## return ftrc
##@trampoline2(**kwargs)
##def ftt1(**kwargs):
## return ftt(kwargs['p1'],kwargs['p2'])
def ftr(p1,p2):
if (p2 == 4):
return (p1,p2)
ftr(p1+1,p2+2)
def ft1(p1,p2):
if (p2==4):
return None
return {'p1': p1+1,'p2': p2+2}
def ft1r(p1,p2):
#
rval = ft1(p1,p2)
while (rval is not None):
lrval = rval
rval = ft1(rval['p1'],rval['p2'])
return lrval
# tail recursion would look like:
def ftcr(p1,p2):
if (p2 == 4):
return (p1,p2)
return ftcr(p1+1,p2+2)
"""
What we're really trying to do, however, is come up with a general
way to handle a closure and use it to enclose some state so that it's
wrapped up there and available between invocations?
"""