简体   繁体   English

类型同义词的类限制?

[英]Class restriction for type synonyms?

I want to do something like: (In pseudocode; this does not compile) 我想做类似的事情:(在伪代码中;这不会编译)

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

or possibly 或者可能

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

But I cannot do this. 但我不能这样做。

After reading up I have a feeling that to achieve this I need the RankNTypes extension or the forall keyword, but I just can't wrap my mind around this... 在阅读之后,我有一种感觉,要实现这一点,我需要RankNTypes扩展或forall关键字,但我无法围绕这个...

Can anyone help? 有人可以帮忙吗?

EDIT: I managed, but rather by "guessing around syntax": The solution is, indeed with RankNTypes : 编辑:我管理,而是通过“猜测语法”:解决方案是,确实与RankNTypes

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

This works, but with the RankNTypes extension 这有效,但具有RankNTypes扩展名

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

works equally. 同样有效。 What's the difference, and how does a Num a => constraint, which seems quite natural, relate to rank n types? 有什么区别, Num a =>约束(看起来很自然)如何与n级类型相关?

So the question is still open, but I'm looking for an explanation, rather than a solution. 所以问题仍然存在,但我正在寻找解释,而不是解决方案。

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

is the same thing as 是一样的

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

The reason is that every type variable without a corresponding forall is implicitly introduced by GHC at the topmost type variable scope, for example: 原因是GHC在最顶层的类型变量范围中隐式引入了没有相应forall每个类型变量,例如:

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

For the most part type synonyms are just syntactic convenience, so whenever you see Vec in a type signature, you can just put parentheses around its definition and substitute: 在大多数情况下,类型同义词只是语法上的便利,因此每当您在类型签名中看到Vec时,您只需将括号括在其定义周围并替换:

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

There is one weird exception, where you can't just blindly substitute in the types. 有一个奇怪的例外,你不能盲目地替换类型。 If you have a type synonym like this: 如果你有这样的类型同义词:

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

then the Num constraint floats out to the outermost scope after substitution: 然后Num约束在替换后浮动到最外层范围:

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

and multiple constraints on the same type variable merge: 和相同类型变量合并的多个约束:

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)

In the above cases the class constraint didn't introduce higher-rankedness, because the constraints were bound to variables in the outer scope. 在上面的例子中,类约束没有引入更高的排名,因为约束被绑定到外部范围中的变量。 However, when we use the synonym inside data constructors, the constraint turns into an implicit (existential) dictionary: 但是,当我们在数据构造函数中使用同义词时,约束将变为隐式(存在)字典:

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.

So, to summarize, the behaviour of these kinds of constraints in type synonyms is rather wobbly. 因此,总而言之,类型同义词中这些约束的行为相当不稳定。 We need RankNTypes or Rank2Types to write them out, but this seems to be more of an implementation artifact than anything else. 我们需要RankNTypesRank2Types来编写它们,但这似乎更像是一个实现工件而不是其他任何东西。 We could argue that the syntax can be used to introduce quantifiers to types, and this sort of justifies the RankNType requirement, but we could equally say that it's reasonable that the compiler should detect whether there are fresh quantifiers or not, and proceed accordingly (like it's already being done with the introduced existentials...). 我们可以争辩说语法可以用来向类型引入量词,这种类型证明了RankNType要求,但我们同样可以说编译器应该检测是否有新的量词是合理的,并相应地进行(如它已经完成了引入的存在...)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM