from collections.abc import Iterable, Sequence, Iterator, Container from typing import TypeVar, Union, _SpecialForm, _type_check class Error: def __init__(self, message): self.message = message T = TypeVar("T") @_SpecialForm def Result(self, parameters): """Result type. Result[T] is equivalent to Union[T, Error]. """ arg = _type_check(parameters, f"{self} requires a single type.") return Union[arg, Error] def is_ok(obj: Result[T]) -> bool: return not isinstance(obj, Error) def in_operator(x, y): if type(y) == type: if isinstance(x, y): return True elif is_ok(y.try_new(x)): return True # TODO: trait check return False elif (issubclass(type(y), list) or issubclass(type(y), set)) \ and (type(y[0]) == type or issubclass(type(y[0]), Range)): # FIXME: type_check = in_operator(x[0], y[0]) len_check = len(x) == len(y) return type_check and len_check elif issubclass(type(y), dict) and issubclass(type(next(iter(y.keys()))), type): # TODO: type_check = True # in_operator(x[next(iter(x.keys()))], next(iter(y.keys()))) len_check = len(x) >= len(y) return type_check and len_check else: return x in y class Nat(int): def try_new(i: int): # -> Result[Nat] if i >= 0: return Nat(i) else: return Error("Nat can't be negative") def times(self, f): for _ in range(self): f() class Bool(Nat): def try_new(b: bool): # -> Result[Nat] if b == True or b == False: return Bool(b) else: return Error("Bool can't be other than True or False") def __str__(self) -> str: if self: return "True" else: return "False" def __repr__(self) -> str: return self.__str__() class Str(str): def __instancecheck__(cls, obj): return isinstance(obj, str) def try_new(s: str): # -> Result[Nat] if isinstance(s, str): return Str(s) else: return Error("Str can't be other than str") class Range: def __init__(self, start, end): self.start = start self.end = end def __contains__(self, item): pass def __getitem__(self, item): res = self.start + item if res in self: return res else: raise IndexError("Index out of range") def __len__(self): if self.start in self: if self.end in self: # len(1..4) == 4 return self.end - self.start + 1 else: # len(1..<4) == 3 return self.end - self.start else: if self.end in self: # len(1<..4) == 3 return self.end - self.start else: # len(1<..<4) == 2 return self.end - self.start - 2 def __iter__(self): return RangeIterator(rng=self) Sequence.register(Range) Container.register(Range) Iterable.register(Range) # represents `start<..end` class LeftOpenRange(Range): def __contains__(self, item): return self.start < item <= self.end # represents `start..