Initial Commit
This commit is contained in:
commit
6e83111276
3 changed files with 122 additions and 0 deletions
40
tail_recurse/__init__.py
Normal file
40
tail_recurse/__init__.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
"""
|
||||
Python Decorator that enables tail call
|
||||
optimization through Exception Trampolines.
|
||||
"""
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List
|
||||
import functools
|
||||
import inspect
|
||||
|
||||
@dataclass
|
||||
class TailRecurseException(Exception):
|
||||
"""Exception to enable tail call recursion."""
|
||||
args: List[Any] = field(default_factory=list)
|
||||
kwargs: Dict[Any, Any] = field(default_factory=dict)
|
||||
|
||||
def tail_call(func):
|
||||
"""
|
||||
Decorator that performs tail call optimization.
|
||||
|
||||
Notes
|
||||
=====
|
||||
Works by throwing an exception to exit the stack
|
||||
when the function sees itself as its grandparent in
|
||||
the stack trace. It then calls itself with its new
|
||||
arguments.
|
||||
"""
|
||||
@functools.wraps(func)
|
||||
def recurse(*args, **kwargs):
|
||||
frame = inspect.currentframe()
|
||||
if frame.f_back is not None \
|
||||
and frame.f_back.f_back is not None \
|
||||
and frame.f_back.f_back.f_code == frame.f_code:
|
||||
raise TailRecurseException(args, kwargs)
|
||||
while True:
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except TailRecurseException as exception:
|
||||
args = exception.args
|
||||
kwargs = exception.kwargs
|
||||
return recurse
|
Loading…
Add table
Add a link
Reference in a new issue