简体   繁体   English

如何通过减少良好类型的函数来减少类型错误?

[英]How can eta-reduction of a well typed function result in a type error?

I was playing around with van Laarhoven lenses and ran into a problem where the type-checker rejects the eta-reduced form of a well-typed function: 我正在玩van Laarhoven镜头并遇到一个问题,其中类型检查器拒绝了et-reduced形式的良好类型的功能:

{-# LANGUAGE RankNTypes #-}

import Control.Applicative

type Lens c a = forall f . Functor f => (a -> f a) -> (c -> f c)

getWith :: (a -> b) -> ((a -> Const b a) -> (c -> Const b c)) -> (c -> b)
getWith f l = getConst . l (Const . f)

get :: Lens c a -> c -> a
get lens = getWith id lens

The above type-checks but if I eta-reduce get to 上面的类型检查,但如果我eta-reduce get

get :: Lens c a -> c -> a
get = getWith id

Then GHC (7.4.2) complains that 然后GHC(7.4.2)抱怨说

Couldn't match expected type `Lens c a'
            with actual type `(a0 -> Const b0 a0) -> c0 -> Const b0 c0'
Expected type: Lens c a -> c -> a
  Actual type: ((a0 -> Const b0 a0) -> c0 -> Const b0 c0)
               -> c0 -> b0
In the return type of a call of `getWith'
In the expression: getWith id

I can understand that if the function didn't have an explicit type-signature then eta-reduction in combination with the monomorphism restriction might confuse the type inference, especially when we are dealing with higher rank types, but in this case I'm not sure what's going on. 我可以理解,如果函数没有明确的类型签名,那么结合单同性限制的eta-reduction可能会混淆类型推断,特别是当我们处理更高级别的类型时,但在这种情况下我不是确定发生了什么。

What causes GHC to reject the eta-reduced form and is this a bug/limitation in GHC or some fundamental problem with higher rank types? 是什么导致GHC拒绝eta减少形式,这是GHC中的错误/限制或更高等级类型的一些基本问题?

I'd say that the reason isn't in the η-reduction itself, the problem is that with RankNTypes you lose principal types and type inference. 我要说的原因不在于η-减少本身,问题在于使用RankNTypes你会丢失主要类型和类型推断。

The problem with type inference with higher-order ranks is when inferring the type of λx.M to obey the rule 高阶排序类型推断的问题是在推断遵循规则的λx.M的类型时

     Γ, x:σ |- M:ρ
----------------------
  Γ |- λx:σ.M : σ→ρ

we don't know what type σ we should choose for x . 我们不知道我们应该为x选择什么类型的σ。 In the case of Hindley-Milner type system, we limit ourselves to type-quantifier-free types for x and the inference is possible, but not with arbitrary ranked types. 在Hindley-Milner类型系统的情况下,我们将自己限制为x类型 - 量词 - 无类型,并且推理是可能的,但不是任意排序类型。

So even with RankNTypes , when the compiler encounters a term without explicit type information, it resorts to Hindley-Milner and infers its rank-1 principal type. 因此,即使使用RankNTypes ,当编译器遇到没有显式类型信息的术语时,它会转向Hindley-Milner并推断出它的rank-1主体类型。 However, in your case the type you need for getWith id is rank-2 and so compiler can't infer it by itself. 但是,在您的情况下, getWith id所需的类型是rank-2,因此编译器无法自行推断它。

Your explicit case 你的明确案例

get lens = getWith id lens

corresponds to the situation where the type of x is already given explicitly λ(x:σ).Mx . 对应于已经明确给出x的类型λ(x:σ).Mx The compiler knows the type of lens before type-checking getWith id lens . 在类型检查getWith id lens之前,编译器知道lens类型。

In the reduced case 在减少的情况下

get = getWith id

the compiler has to infer the type of getWidth id on it's own, so it sticks with Hindley-Milner and infers the inadequate rank-1 type. 编译器必须自己推断getWidth id的类型,因此它坚持使用Hindley-Milner并推断出rank-1类型不足。

Actually it's quite straight-forward: GHC infers the types per expression , then starts to unify them across = . 实际上它非常简单:GHC推断每个表达式的类型,然后开始将它们统一在= This works always fine when there are only rank-1-types around, because the most polymorphic one is chosen (that's well-defined); 当只有rank-1类型时,这总是很好,因为选择了最多态的(这是明确定义的); so any unification that's possible at all will succeed. 所以任何可能的统一都会成功。

But it will not choose a more general rank-2-type even if that would be possible, so getWith id is inferred to be ((a -> Const aa) -> c -> Const ac) -> (c -> a) rather than (forall f . Functor f => (a -> fa) -> c -> fc) -> (c -> a) . 但它不会选择更一般的rank-2-type,即使这是可能的,所以getWith id被推断为((a -> Const aa) -> c -> Const ac) -> (c -> a) ,而不是(forall f . Functor f => (a -> fa) -> c -> fc) -> (c -> a) I suppose if GHC did do such stuff, traditional rank-1 type inference wouldn't work at all anymore. 我想如果GHC确实做了这样的事情,传统的1级类型推断就不再适用了。 Or it would just never terminate, because there doesn't exist one well-defined most polymorphic rank-n type. 或者它永远不会终止,因为不存在一个明确定义的最多态的rank-n类型。

That doesn't explain why it can't see from get 's signature that it needs to choose rank-2 here, but presumably there is a good reason for that as well. 这并没有解释为什么它不能从get的签名中看到它需要在这里选择排名-2,但可能也有一个很好的理由。

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

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