为什么强制性多态只允许用于Haskell中的函数?

时间:2019-06-04 17:35:59

标签: haskell polymorphism rank-n-types impredicativetypes

在Haskell中我不会写

f :: [forall a. a -> a]
f = [id]

因为

• Illegal polymorphic type: forall a. a -> a
  GHC doesn't yet support impredicative polymorphism

但是我可以开心地做

f :: (forall a. a -> a) -> (a, b) -> (a, b)
f i (x, y) = (i x, i y)

因此,我看到GHC确实支持强制性多态性,这与上面的错误消息相反。为什么在这种情况下特别对待(->)类型的构造函数?是什么使GHC无法将此功能推广到所有数据类型?

1 个答案:

答案 0 :(得分:12)

高级多态性是强制性多态性的特例,其中类型构造函数为(->),而不是诸如[]之类的任意构造函数。

不可预测性的基本问题是,它使类型 checking 变得很难,而类型 inference 变得不可能-实际上我们不能推断出等级高于2的类型:必须提供类型注释。这就是存在与Rank2Types分开的RankNTypes扩展名的原因。但是对于(->)的受限情况,有简化的算法可以检查这些类型并为程序员的方便起见进行必要的推理,例如Complete and Easy Bidirectional Type Checking for Higher-rank Polymorphism,这与{ {3}}。

GHC的实际原因部分是历史原因: 有一个ImpredicativeTypes扩展名,现在已弃用,但从未正常工作或符合人体工程学。问题的部分原因是我们还没有TypeApplications扩展名,因此没有方便的方法来显式提供多态类型作为类型实参,并且编译器尝试进行更多的推断。现在我们有了TypeApplications,将来可能会成为ImpredicativeTypes的受限形式。

但是,这并不是很紧迫,因为已经有一段时间了解决方法:使用RankNTypes,您可以通过将多态类型包装在newtype中并显式打包来“隐藏”其他形式的隐含性并将其解压缩,以告诉编译器您要在何处泛化和实例化类型变量的确切位置。

newtype Id = Id { unId :: forall a. a -> a }

f :: [Id]
f = [Id id]  -- generalise

(unId (head f) (), unId (head f) 'x')  -- instantiate to () and Char