from typing import TypeVar, Generic, Union, Optional from dataclasses import dataclass from enum import Enum, auto carrier = TypeVar('carrier') item = TypeVar('item') @dataclass class List(Generic[item]): def cata(self,a): return a.cata(self) @dataclass class Nil(List[item]): pass @dataclass class Cons(List[item]): head: item tail: List[item] class op(Enum): Add = auto() Sub = auto() Mul = auto() def carrier(self) -> item: match self: case op.Add: return 0 case op.Sub: return 0 case op.Mul: return 1 def eval(self, a: item, b:item) -> item: match self: case op.Add: return a + b case op.Sub: return a - b case op.Mul: return a * b @dataclass class Functor(Generic[item, carrier]): method: op cons: list[item, carrier] def ieval(xs, carrier: Optional[item] = None) -> item: match xs: case Nil(): return carrier case Functor(m, Cons(h, t)): return m.eval( ieval(h, m.carrier()), ieval(t, m.carrier()) ) case i: return i def test_eval_add(): x = Functor( op.Add, Cons( 1, Functor( op.Add, Cons( 2, 3 ) ) ) ) assert ieval(x) == 6 if __name__ == "__main__": test_eval_add()