Haskell中的多态之参数多态
参数多态
参数多态在程序设计语言与类型论中是指声明与定义函数、复合类型、变量时不指定其具体的类型,而把这部分类型作为参数使用,使得该定义对各种具体类型都适用
例如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
是合法的,但如果取a
为Int
,f
的类型就为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
的,由此可知,如果一个类型的类型参数中最高Rank
为N
,那么这个类型就是Rank-N+1
的。
可以将参数多态类型理解类比为函数,它们有如下的对应关系:
参数多态类型 | 函数 |
---|---|
类型参数 | 函数参数 |
类型参数为简单类型变量(a, b, c..) | 函数参数类型为简单类型(a, b, c..) |
类型参数为参数多态类型 | 函数参数为函数 |
参数多态类型是Rank-N的 | 函数的Rank为N |
类型参数为Rank-N的,那么此参数多态类型为Rank-N+1的 | 函数参数的Rank为N,那么此函数的Rank为N+1 |