【问题标题】:Why doesn't forall (RankNTypes usage) apply by default?为什么默认情况下不适用 forall(RankNTypes 用法)?
【发布时间】:2012-04-25 03:00:23
【问题描述】:

我对@9​​87654322@不是很熟悉,但是最近看了这个问题:What does the `forall` keyword in Haskell/GHC do?

答案之一是这个例子:

 {-# LANGUAGE RankNTypes #-}
 liftTup :: (forall x. x -> f x) -> (a, b) -> (f a, f b)
 liftTup liftFunc (t, v) = (liftFunc t, liftFunc v)

解释很好,我明白forall 在这里做什么。但我想知道,这不是默认行为是否有特殊原因。有没有不利的时候?

编辑:我的意思是,默认情况下无法插入 forall 是否有原因?

【问题讨论】:

  • 您是在问为什么默认情况下没有打开扩展程序,或者为什么 (x -> f x) -> (a,b) -> (f a, f b) 不被视为与 (forall x. x -> f x) -> (a, b) -> (f a, f b) 相同?如果是后者,您能否指定您建议编译器决定在哪里插入foralls 的逻辑?
  • 后者,我不知道从哪里开始就这个主题提出任何建议!
  • 请注意,(x -> f x) -> (a, b) -> (f a, f b) 类型相当无用。该函数不能将第一个参数应用于元组的任一元素,因此其结果必须是 (⊥, ⊥)

标签: haskell ghc


【解决方案1】:

我怀疑默认情况下没有启用更高等级的类型,因为they make type inference undecidable。这也是为什么,即使启用了扩展,您也需要使用 forall 关键字来获得更高级别的类型 - GHC 假定所有类型都是 rank-1 除非明确告知,以便推断出尽可能多的类型信息可能。

换句话说,没有通用的方法可以推断出更高级别的类型(forall x. x -> f x) -> (a,b) -> (f a, f b),因此获得该类型的唯一方法是通过显式类型签名。

编辑:根据上面 Vitus 的 cmets,rank-2 类型推断是可确定的,但更高级别的多态性不是。所以这种类型签名在技术上是可推断的(尽管算法更复杂)。启用 rank-2 多态类型推断的额外复杂性是否值得值得商榷......

【讨论】:

    【解决方案2】:

    嗯,它不是 Haskell 2010 标准的一部分,因此默认情况下不启用,而是作为语言扩展提供。至于为什么它不在标准中,rank-n 类型比标准 Haskell 的普通 rank-1 类型更难实现;它们也不是那么频繁地需要,因此出于语言和实现简单的原因,委员会可能决定不打扰它们。

    当然,这并不意味着 rank-n 类型没有用;它们确实如此,没有它们,我们就没有像ST monad 这样的有价值的工具(它提供了高效的本地可变状态——比如IO,你所能做的就是使用IORefs)。但是它们确实给语言增加了相当多的复杂性,并且在应用看似良性的代码转换时可能会导致奇怪的行为。例如,一些 rank-n 类型检查器将允许 runST (do { ... }) 但拒绝 runST $ do { ... },即使这两个表达式在没有 rank-n 类型时总是等价的。请参阅 this SO question 了解它可能导致的意外(有时是令人讨厌的)行为的示例。

    如果像 sepp2k 所问的那样,您是在问为什么必须将 forall 显式添加到类型签名中以提高通用性,那么问题是 (forall x. x -> f x) -> (a, b) -> (f a, f b) 实际上是比 (x -> f x) -> (a, b) -> (f a, f b) 更具限制性的类型。对于后者,您可以传入x -> f x 形式的任何函数(对于任何fx),但对于前者,您传入的函数必须适用于all @ 987654335@。因此,例如,String -> IO String 类型的函数将是第二个函数的允许参数,但不是第一个函数;它必须具有 a -> IO a 类型。如果后者自动转换为前者,那将是相当混乱的!它们是两种截然不同的类型。

    隐含的foralls 可能更有意义:

    forall f x a b. (x -> f x)           -> (a, b) -> (f a, f b)
    forall f a b.   (forall x. x -> f x) -> (a, b) -> (f a, f b)
    

    【讨论】:

    • 我想我需要再消化一下 :)
    • 另外,对于二阶和更高阶的多态性,没有最通用的类​​型,∀ b. (∀ a. a → b) → (b, b) 并不比∀ c d. (∀ a b. a → b) → (c, d) 更通用,反之亦然。虽然类型推断对于一阶和二阶多态性是可判定的,但对于三阶和更高阶则不是。
    • @vitus - 你能为二阶多态性的可判定性提供参考吗?我不熟悉它。
    • @JohnL:我在this wikipedia article 中找到了它,它又引用了 Pierce 的类型和编程语言。
    • @JohnL:应该在第 23.8 章。 (系统 F 的 2 级多态性限制):Kfoury 和 Wells(1999)给出了第 2 级系统的第一个正确类型重建算法,并表明系统 F 的 3 级及更高级别的类型重建是不可判定的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-13
    • 2021-11-21
    • 2015-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多