Skip to content

Instantly share code, notes, and snippets.

@L3viathan
Last active July 24, 2023 15:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save L3viathan/8bc92404f7084342175b95970a086b04 to your computer and use it in GitHub Desktop.
Save L3viathan/8bc92404f7084342175b95970a086b04 to your computer and use it in GitHub Desktop.
Sum types in Python
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
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