类型同义词的类限制?

时间:2014-06-24 07:44:15

标签: haskell

我想做的事情如下: (在伪代码中;这不能编译)

type Num a => Vector2d = (a,a)

或可能

type Num a => Vector2d a = (a,a)

但我不能这样做。

阅读后我觉得要实现这一目标,我需要RankNTypes扩展程序或forall关键字,但我无法理解这个...

有人可以帮忙吗?

编辑: 我管理,而是通过"猜测语法": 解决方案确实是RankNTypes

type Vec =  forall a. Num a => (a,a)

这样可行,但RankNTypes扩展程序

type Vec = Num a => (a,a)

同样有效。差异是什么,Num a =>约束(看起来很自然)与排名 n 类型有什么关系?

所以问题仍然存在,但我正在寻找解释,而不是解决方案。

1 个答案:

答案 0 :(得分:6)

type Vec = forall a. Num a => (a, a)

相同

type Vec = Num a => (a, a)

原因是GHC在最顶层的类型变量范围内隐式引入了没有相应forall的每个类型变量,例如:

const :: a -> b -> a
const :: forall a b. a -> b -> a -- the same thing

在大多数情况下,类型同义词只是语法上的便利,因此每当您在类型签名中看到Vec时,您只需将括号括在其定义周围并替换:

Vec -> Vec -> Integer
-- equals:
(forall a. Num a => (a, a)) -> (forall a. Num a => (a, a)) -> Integer

有一个奇怪的例外,你不能盲目地在类型中替换。如果您有类似的同义词:

type Vec a = Num a => (a, a) 

然后Num约束在替换后浮动到最外层范围:

vec = (100, 100) :: Vec Integer
-- vec has now type "(Integer, Integer)"

和相同类型变量的多个约束合并:

addVec :: Vec a -> Vec a -> Vec a
addVec (a, b) (c, d) = (a + c, b + d)
-- addVec has now effectively type "Num a => (a, a) -> (a, a) -> (a, a)

在上述情况下,类约束没有引入更高排名,因为约束绑定到外部范围中的变量。但是,当我们在数据构造函数中使用同义词时,约束将变为隐式(存在)字典:

type Foo a = Num a => a 
data Bar a = Bar (Foo a) -- equals "data Bar a = Bar (Num a => a)"
-- requires ExistentialQuantifiaction or GADTs to compile

-- and of course, any data constructor blocks the outwards floating of the constraint:
type Baz = a -> (Foo a, ()) -- requires ImpredicativeTypes.

因此,总而言之,类型同义词中这些约束的行为相当不稳定。我们需要RankNTypesRank2Types来编写它们,但这似乎更像是一个实现工件而不是其他任何东西。我们可以争辩说语法可以用来向类型引入量词,这种证明RankNType要求是合理的,但我们同样可以说编译器应该检测是否合理是否是新的量词,并相应地进行(就像它已经完成了引入的存在...)。