我有一个行为 X 和一个带有参数类型的回调函数:
%{a: any}
模块 Y 实现行为 X 并且实现模块 Y 中的回调函数具有参数类型:
%{a: any, b: any}
Dialyzer 不喜欢这样并抱怨:
(#{'a':=_, 'b':=_, _=>_})
is not a supertype of
#{'a':=_}
这意味着透析器尝试确定实现模块 Y 中的回调参数类型是否是行为 X 中的参数类型的超类型。换句话说,它要求:
行为 X 的回调参数类型
%{a: any}
是实现模块 Y 的参数类型的子类型%{a: any, b: any}
吗?
为什么透析器期望行为回调的参数类型是子类型而不是超类型?
在编程语言类型论的上下文中,子类型定义为:
类型 S 是类型 T 的子类型,写作 S <: T,如果类型 S 的表达式可以在任何需要类型 T 的元素的上下文中使用。另一种说法是任何类型 S 的表达式都可以伪装作为类型 T 的表达式。
T
根据上面的定义,如果行为回调的参数类型是,实现模块的参数类型是,对我来说是有意义的S
。因为实现模块仍然保持行为契约。但是,我不知道为什么透析器期望相反。
请帮助我理解这一点。
注意:这个问题是后续问题,但独立于另一个 SO 问题Erlang (Elixir) Dialyzer - 令人困惑的超类型错误。