Last active
July 4, 2025 20:29
-
-
Save aarondewindt/1cb0af45f05c0da03bfbec6f050f5b58 to your computer and use it in GitHub Desktop.
Experimental Algebraic Data Types implementation in Python 3.10
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 dataclasses import dataclass | |
| class ADTMeta(type): | |
| def __new__(mcs, name, bases, namespace: dict): | |
| adtc_class = super().__new__(mcs, name, bases, namespace) | |
| if "__is_adt_variant__" in namespace: | |
| if namespace["__is_adt_variant__"]: | |
| return adtc_class | |
| for member_name, member in namespace.items(): | |
| if isinstance(member, type): | |
| variant_class = dataclass(type(member_name, (adtc_class,), { | |
| "__qualname__": f"{adtc_class.__qualname__}.{member_name}", | |
| "__is_adt_variant__": True, | |
| "__annotations__": member.__annotations__ | |
| })) | |
| setattr(adtc_class, member_name, variant_class) | |
| annotations = namespace.pop("__annotations__", {}) | |
| for variant_name, variant_annotation in annotations.items(): | |
| variant_class = type(variant_name, (adtc_class,), { | |
| "__qualname__": f"{adtc_class.__qualname__}.{variant_name}", | |
| "__is_adt_variant__": True | |
| }) | |
| if (variant_annotation is Ellipsis) or (variant_annotation is None): | |
| variant_class.__repr__ = lambda self: f"<{self.__class__.__qualname__}>" | |
| else: | |
| variant_class.__init__ = create_init(variant_class, variant_annotation) | |
| variant_class.__repr__ = lambda self: f"<{self.__class__.__qualname__} {repr(self.value)}>" | |
| variant_class.__match_args__ = ("value",) | |
| setattr(adtc_class, variant_name, variant_class) | |
| return adtc_class | |
| def create_init(klass, annotation): | |
| def __init__(self: klass, value: annotation) -> None: | |
| self.value = value | |
| return __init__ |
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 adt import ADTMeta | |
| class Foo(metaclass=ADTMeta): | |
| a: ... | |
| b: tuple[int, str, int] | |
| c: str | |
| class d: | |
| da: str | |
| db: int | |
| dc: tuple[float, float] | |
| assert issubclass(Foo.a, Foo) | |
| assert issubclass(Foo.b, Foo) | |
| assert issubclass(Foo.c, Foo) | |
| assert issubclass(Foo.d, Foo) | |
| value = Foo.a() | |
| value = Foo.b((1, "Hello", 1234)) | |
| value = Foo.b((1, "World", 42)) | |
| # value = Foo.c("Bar") | |
| # value = Foo.d("Baz", 69, (1.2, 3.5)) | |
| # value = Foo.d("positional", 69, (1.2, 3.5)) | |
| match value: | |
| case Foo.a(): | |
| print("Matched Foo.a") | |
| case Foo.b((val_int_1, val_str, 42)): | |
| print(f"Matched Foo.b with {val_int_1} {val_str} and the answer of life, the universe and everything") | |
| case Foo.b((val_int_1, val_str, val_int_2)): | |
| print(f"Matched Foo.b with {val_int_1} {val_str} {val_int_2}") | |
| case Foo.c(val_str): | |
| print(f"Matched Foo.c with {val_str}") | |
| case Foo.d("positional", val_int, (f1, f2)): | |
| print(f"Matched d with positional pattern db={val_int} dc=({f1}, {f2})") | |
| case Foo.d(da=val_str, db=val_int, dc=(f1, f2)): | |
| print(f"Matched d with da={val_str} db={val_int} dc=({f1}, {f2})") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment