class Bool(int):
pass
class Int(int):
pass
T = typing.TypeVar("T", Bool, Int)
class MyGenericAlias(typing._GenericAlias, _root=True):
def __subclasscheck__(self, cls):
for cls_parent in cls.mro():
for base in cls_parent.__orig_bases__:
return (
issubclass(self.__origin__, base.__origin__)
and len(self.__args__) == len(base.__args__)
and all(issubclass(self_arg, cls_arg) for (self_arg, cls_arg) in zip(self.__args__, base.__args__))
)
class Protocol(typing.Generic):
pass
class MyGeneric(Protocol):
def __instancecheck__(self, obj):
print(self, obj)
return super().__instancecheck__(obj)
def __class_getitem__(cls, params):
return MyGenericAlias(cls, params)
@typing.sealed
class Expr(MyGeneric[T]):
pass
@dataclasses.dataclass
class EBool(Expr[Bool]):
b: Bool
@dataclasses.dataclass
class EInt(Expr[Int]):
n: Int
@dataclasses.dataclass
class EEqual(Expr[Bool]):
l: Expr[Int]
r: Expr[Int]
def eeval(e: Expr[T]) -> T:
match e:
case EBool(b):
return b
case EInt(n):
return n
case EEqual(l, r):
return eeval(l) == eeval(r)
a = EInt(42)
b = EInt(21)
c = EEqual(a, b)
print("a", eeval(a))
print("b", eeval(b))
print("c", eeval(c))
print("c is an Expr[Int]: ", isinstance(c, Expr[Int]))
print("c is an Expr[Bool]:", isinstance(c, Expr[Bool]))