Last active
July 24, 2023 15:31
-
-
Save L3viathan/8bc92404f7084342175b95970a086b04 to your computer and use it in GitHub Desktop.
Sum types in Python
This file contains 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
class SubscriptableSneaky: | |
def __init__(self, ns, name): | |
self.ns = ns | |
self.args = [] | |
self.name = name | |
def __getitem__(self, items): | |
if not isinstance(items, tuple): | |
items = items, | |
self.args = [item.name for item in items] | |
self.ns.generics.update(items) | |
def __repr__(self): | |
return f"SS({self.name}, {self.args})" | |
class SneakyNamespace(dict): | |
def __init__(self): | |
self.accessed_names = {} | |
self.generics = set() | |
self.real_ns = {} | |
def __getitem__(self, item): | |
if item not in self.real_ns and not item.startswith("__"): | |
sneaker = SubscriptableSneaky(self, item) | |
self.accessed_names[item] = sneaker | |
return sneaker | |
return self.real_ns[item] | |
def __setitem__(self, item, value): | |
self.real_ns[item] = value | |
def make_box(name, fields): | |
if fields: | |
class Placeholder: | |
__match_args__ = tuple(fields) | |
__slots__ = fields | |
def __init__(self, *args): | |
for name, field in zip(fields, args, strict=True): | |
setattr(self, name, field) | |
def __repr__(self): | |
return f"{name}({', '.join(f'{getattr(self, field)!r}' for field in fields)})" | |
else: | |
class Placeholder(type): | |
def __repr__(self): | |
return name | |
Placeholder.__name__ = name | |
if not fields: | |
Placeholder = Placeholder(name, (), {}) | |
return Placeholder | |
class STMeta(type): | |
def __prepare__(name, *args, **kwargs): | |
return SneakyNamespace() | |
def __new__(self, name, bases, namespace, **kwargs): | |
obj = super().__new__(self, name, bases, namespace, **kwargs) | |
variables = set(namespace.generics) | |
variant_names = set(namespace.accessed_names) - variables | |
variants = {k: v for k, v in namespace.accessed_names.items() if k not in variables} | |
for name, variant in variants.items(): | |
setattr(obj, name, make_box(name, variant.args)) | |
return obj | |
class ST(metaclass=STMeta): | |
pass |
This file contains 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 sumtypes import ST | |
class Result(ST): | |
Ok[T] | |
Err[E] | |
class Maybe(ST): | |
Some[T] | |
Not | |
res = Result.Err("hello") | |
nah = Maybe.Not | |
match res: | |
case Result.Ok(value): | |
print("got a result:", value) | |
case Result.Err(): | |
print("got an error") | |
match nah: | |
case Maybe.Not: | |
print("not good") | |
case Maybe.Some(value): | |
print("some value:", value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment