Last active
January 8, 2022 17:16
-
-
Save hurryabit/a7213d9c8d059c31f51686bd66691592 to your computer and use it in GitHub Desktop.
Stack-safety for free?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This gist contains the Python version of the code from the blog post | |
# https://hurryabit.github.io/blog/stack-safety-for-free/ | |
import sys | |
from typing import Callable, Generator, TypeVar | |
Arg = TypeVar("Arg") | |
Res = TypeVar("Res") | |
def triangular(n: int) -> int: | |
if n == 0: | |
return 0 | |
else: | |
return n + triangular(n - 1) | |
def trampoline(f: Callable[[Arg], Generator[Arg, Res, Res]]) -> Callable[[Arg], Res]: | |
def mu_f(arg: Arg) -> Res: | |
stack = [] | |
current = f(arg) | |
res: B = None # type: ignore | |
while True: | |
try: | |
arg = current.send(res) | |
stack.append(current) | |
current = f(arg) | |
res = None # type: ignore | |
except StopIteration as stop: | |
if len(stack) > 0: | |
current = stack.pop() | |
res = stop.value | |
else: | |
return stop.value | |
return mu_f | |
@trampoline | |
def triangular_safe(n: int) -> Generator[int, int, int]: | |
if n == 0: | |
return 0 | |
else: | |
return n + (yield (n - 1)) | |
LARGE: int = sys.getrecursionlimit() + 1 | |
assert triangular_safe(LARGE) == LARGE * (LARGE + 1) // 2 | |
print("`triangular_safe` has not overflowed its stack.") | |
print("`triangular` will overflow its stack soon...") | |
try: | |
triangular(LARGE) | |
raise Exception("`triangular` has not overflowed its stack.") | |
except RecursionError: | |
print("`triangular` has overflowed its stack.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment