参数多态

参数多态在程序设计语言与类型论中是指声明与定义函数、复合类型、变量时不指定其具体的类型,而把这部分类型作为参数使用,使得该定义对各种具体类型都适用

例如Haskell的id函数:

id :: forall a. a -> a
id x = x

id函数的签名可以解释为:对于任意类型a,如果x的类型是a,那么id x都是合法的,所以id "abc", id 1, id True等调用都是合法的

而像not :: Bool -> Bool 这样的函数则只能以Bool类型的值为参数

RankN-Type

再考虑以下的函数

foo :: forall a. (a -> a) ->  Bool
foo f = f True

是不能编译通过的,因为按照foo的签名,对于任意类型a,如果f的类型是a -> a,都应该保证foo f是合法的,但如果取aIntf的类型就为Int -> Int,但是f True显然就不合法了。另一种更简单的解释是:这里f的类型是a -> a,但是你却给f传了个Bool类型的值,当然就类型不匹配了,GHC的报错信息就是这样的,这说明,foo是一个多态函数,而f却不是。

解决这个问题的方法是开启GHC的RankNTypes扩展并写成下面的样子:

foo' :: (forall a. a -> a) -> Bool
foo' f = f True

我们只是加了一层括号,但是签名的含义发生了很大的变化——如果f的类型为forall a. a -> a,那么foo' f是合法的,由于id的类型为forall a. a -> a,因此foo' id是合法的。可以看出,现在我们要求f是一个多态函数,当然foo'也还是一个多态函数,但这种多态已经和id不是一回事了。

id这样类型参数只是简单的类型变量(而不是参数多态类型)的参数多态类型被称作是Rank-1的,而像foo'这样其类型参数是一个Rank-1的参数多态类型被称为是Rank-2的,由此可知,如果一个类型的类型参数中最高RankN,那么这个类型就是Rank-N+1的。

可以将参数多态类型理解类比为函数,它们有如下的对应关系:

参数多态类型 函数
类型参数 函数参数
类型参数为简单类型变量(a, b, c..) 函数参数类型为简单类型(a, b, c..)
类型参数为参数多态类型 函数参数为函数
参数多态类型是Rank-N的 函数的Rank为N
类型参数为Rank-N的,那么此参数多态类型为Rank-N+1的 函数参数的Rank为N,那么此函数的Rank为N+1