Skip to content

Instantly share code, notes, and snippets.

@tomerfiliba
Created January 25, 2012 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomerfiliba/1676662 to your computer and use it in GitHub Desktop.
Save tomerfiliba/1676662 to your computer and use it in GitHub Desktop.
Tail call optimization
#
# By Nimrod Aviram and Eyal Lotem
#
import functools
class TailCallFunc(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
res = self.func(*args, **kwargs)
while True:
if not isinstance(res, tailCall):
return res
res = res.func(*res.args, **res.kwargs)
def tailCall(self, *args, **kwargs):
return self.func(*args, **kwargs)
def __get__(self, obj, type):
return functools.partial(self, obj)
class tailCall(object):
def __init__(self, func):
self.alreadyCalled = False
if isinstance(func, TailCallFunc):
self.func = func.func
else:
self.func = func
def __call__(self, *args, **kwargs):
if self.alreadyCalled:
raise
self.args = args
self.kwargs = kwargs
self.alreadyCalled = True
return self
@TailCallFunc
def f(x):
if x == 0:
return 'qwe'
return tailCall(f)(x - 1)
assert f(10010) == 'qwe'
class Maybe(object):
def __init__(self, *value):
if value:
[self.value] = value
self.isJust = True
else:
self.isJust = False
@classmethod
def wrap(cls, *args, **kw):
return cls(*args, **kw)
@TailCallFunc
def bind(self, f):
if self.isJust:
return tailCall(f)(self.value)
return self
assert Maybe(10010).bind(f) == 'qwe'
# not sure if this ever worked...
@TailCallFunc
def liftM(f, x):
wrap = type(x).wrap
return tailCall(x.bind)(lambda unwrapped: wrap(f(unwrapped)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment