Created
December 30, 2024 01:09
-
-
Save jepler/6581bf51fc74f4033e6014fe66eb05ae to your computer and use it in GitHub Desktop.
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
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