这是一个相对 Pythonic 方式的 sum 类型的实现。
import attr
@attr.s(frozen=True)
class CombineMode(object):
kind = attr.ib(type=str)
params = attr.ib(factory=list)
def match(self, expected_kind, f):
if self.kind == expected_kind:
return f(*self.params)
else:
return None
@classmethod
def join(cls):
return cls("join")
@classmethod
def select(cls, column: str):
return cls("select", params=[column])
打开一个解释器,你会看到熟悉的行为:
>>> CombineMode.join()
CombineMode(kind='join_by_entity', params=[])
>>> CombineMode.select('a') == CombineMode.select('b')
False
>>> CombineMode.select('a') == CombineMode.select('a')
True
>>> CombineMode.select('foo').match('select', print)
foo
注意:@attr.s 装饰器来自attrs library,它实现了__init__、__repr__ 和__eq__,但它也冻结了对象。我包含它是因为它减少了实现规模,但它也广泛可用且相当稳定。
Sum 类型有时称为标记联合。这里我使用kind 成员来实现标签。附加的每个变量参数通过列表实现。在真正的 Python 风格中,这在输入和输出端是鸭式的,但在内部没有严格执行。
我还包括了一个match 函数,它可以进行基本的模式匹配。类型安全也通过鸭子类型实现,如果传递的 lambda 函数签名与您尝试匹配的实际变体不一致,则会引发 TypeError。
这些总和类型可以与乘积类型(list 或 tuple)结合使用,并且仍然保留代数数据类型所需的许多关键功能。
问题
这并不严格限制变体集。