为何部分应用的类型构造器仅可在类型参数位置传入?
底层规则本质:固定Kind的内置类型构造器 和 支持多态Kind的类型变量 的推导逻辑差异
基础前提:Kind 规则
Haskell 中所有类型构造器都有对应的Kind,可以理解为「类型层面的类型」:
- 可以直接用作值类型的构造器Kind为
*,比如Int、Bool - 带参数的类型构造器的Kind对应类型函数的签名,比如接收1个类型参数的
Maybe的Kind为* -> *,接收2个类型参数的Either的Kind为* -> * -> *
为什么bar会被拒绝
bar :: t [f a] -> f a b -- rejected bar = undefined
[f a]是[] (f a)的语法糖,列表构造器[]是内置的固定Kind的类型,它的Kind是* -> *,只能接收Kind为*的类型作为参数。因此这里可以推导得到:f a的Kind必须是*,进一步可得f的Kind是* -> *。
但返回值里的f a b要求f接收2个类型参数,对应的Kind应该是* -> * -> *,两者推导出来的f的Kind完全冲突,因此编译器直接报错。
为什么foo可以被接受
foo :: t (f a) -> f a b -- accepted foo = undefined
和固定Kind的[]不同,签名里的t、f都是未绑定具体实现的类型变量,编译器会自动推导它们的Kind来满足所有约束,不会有固定Kind的限制:
- 先看返回值
f a b:f需要接收2个*类型的参数a、b,因此f的Kind推导为* -> * -> *,a、b的Kind都是* - 再看参数里的
f a:给Kind为* -> * -> *的f传入1个*类型的a,得到的f a的Kind是* -> * - 最后看
t:它接收f a作为参数,因此t的Kind自动推导为(* -> *) -> *,完全符合规则,没有任何冲突,所以签名可以通过检查。
内容的提问来源于stack exchange,提问作者user5536315
相关产品推荐
相关产品推荐

