" Eta减少"并不总是在哈斯克尔举行?

时间:2013-11-03 22:12:58

标签: haskell higher-rank-types

我发现我可以说

{-# LANGUAGE RankNTypes #-}
f1 :: (forall b.b -> b) -> (forall c.c -> c)
f1 f = id f

(和HLint告诉我,我可以在这里做“Eta reduce”),但是

f2 :: (forall b.b -> b) -> (forall c.c -> c)
f2 = id

无法编译:

Couldn't match expected type `c -> c'
            with actual type `forall b. b -> b'
Expected type: (forall b. b -> b) -> c -> c
  Actual type: (forall b. b -> b) -> forall b. b -> b
In the expression: id
In an equation for `f2': f2 = id

实际上我在更复杂的情况下遇到了类似的问题,但这是我能想到的最简单的例子。因此,HLint无法在此提供适当的建议,或者编译器应检测到这种情况,是吗?

更新

Another revelent question看起来很相似。然而,尽管这两个答案都非常有用,但它们都不能让我满意,因为它们似乎没有触及问题的核心。

例如,我甚至不允许为id分配建议的等级2类型:

f2 :: (forall b.b -> b) -> (forall c.c -> c)
f2 = id :: (forall b.b -> b) -> (forall c.c -> c)

如果问题仅与类型推断有关,则显式类型表示法应解决它(id具有类型a -> a,并且它已被约束为(forall b.b -> b) -> (forall c.c -> c)。因此,为证明此用法,{{1必须匹配(forall b.b -> b),这是真的)。但上面的例子表明情况并非如此。因此,这是“eta reduce”的一个真正的例外:你必须向两边明确地添加参数,以将秩1类型的值转换为秩2的类型值。

但为什么会有这样的限制呢?为什么计算机不能自动统一1级和2级类型(忘记类型推断,所有类型都可以用符号表示)?

1 个答案:

答案 0 :(得分:8)

我不确定HLint是否完全了解RankNTypes,也许不是。

实际上,通过延长,eta减少通常是不可能的。 GHC不能统一a->a(forall b.b -> b) -> (forall c.c -> c),否则会完全搞乱Rank1-code 1 的类型推断能力。 OTOH,将(forall b.b -> b)a参数统一起来并不是一个问题;结果被认为是(forall b.b -> b),与(forall c.c -> c)匹配。


1 考虑map id [(+1), (*2)]。如果允许id具有您正在处理的类型,则编译器可能最终为多态Num函数生成不同的实例选择,这当然是不可能的。还是应该呢?我不确定,想着它......

无论如何,我很确定它证明了使用RankNTypes,完全类型推断是不可能的,所以要至少在Rank1子集中获得它GHC 必须通常默认为不太可能的多态选择。