Skip to content

Instantly share code, notes, and snippets.

@jepler
Created December 30, 2024 01:09
Show Gist options
  • Save jepler/6581bf51fc74f4033e6014fe66eb05ae to your computer and use it in GitHub Desktop.
Save jepler/6581bf51fc74f4033e6014fe66eb05ae to your computer and use it in GitHub Desktop.
from __future__ import annotations
import functools
from typing import Callable, ParamSpec, TypeVar, Generic
P = ParamSpec("P")
T = TypeVar("T")
class Recur(BaseException, Generic[P, T]):
f: Callable[P, T] | None
args: P.args
kwargs: P.kwargs
def __init__(self, f: Recurrent[P, T] | Callable[P, T] | None, *args: P.args, **kwargs: P.kwargs):
super().__init__(*args)
self.f = f.f if isinstance(f, Recurrent) else f
self.kwargs = kwargs
def __call__(self) -> T:
assert self.f is not None
return self.f(*self.args, *self.kwargs)
class Recurrent(Generic[P, T]):
f: Callable[P, T]
def __init__(self, f: Callable[P, T]) -> None:
self.f = f
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
r = Recur(self.f, *args, **kwargs)
while True:
try:
return r()
except Recur as exc:
r.f = r.f if exc.f is None else exc.f
r.args = exc.args
r.kwargs = exc.kwargs
@Recurrent
def gcd(a: int, b: int) -> int:
print(f"gcd({a}, {b})")
if b == 0:
return a
raise Recur(gcd, b, a % b)
@Recurrent
def even(a: int, whatever: str) -> bool:
assert a >= 0
if a == 0: return True
raise Recur(odd, a-1)
@Recurrent
def odd(a: int) -> bool:
assert a >= 0
if a == 0: return False
raise Recur(even, a-1, "boo")
print(gcd(1071, 462))
print(odd(37))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment