代码之家  ›  专栏  ›  技术社区  ›  leftaroundabout

为什么GHC在这里推断出一个单态类型,即使禁用了单态限制?

  •  1
  • leftaroundabout  · 技术社区  · 5 年前

    这是由 Resolving the type of `f = f (<*>) pure` ,它讨论了一个更复杂的示例,但这个示例也适用。

    以下定义编译时没有问题:

    w :: Integral a => a
    w = fromInteger w
    

    …当然没有 工作 从运行时角度看,但这不是问题所在。重点是定义 w 本身使用 专业版 属于 w :: Integer . 显然 一个合适的实例,因此类型检查。

    但是,如果我们删除签名,那么ghc将不推断上述类型,而只推断具体类型:

    w' = fromInteger w'
    
    GHCi> :t w
    w :: Integral a => a
    GHCi> :t w'
    w' :: Integer
    

    好吧,当我看到这个的时候,我相当肯定这是工作中的单态限制。众所周知,例如

    i = 3
    
    GHCi> :t i
    i :: Integer
    

    虽然 i :: Num p => p 是完全可能的。事实上, 我::num p=>p 推断是否 -XNoMonomorphismRestriction 是活动的,即如果禁用了单态限制。

    但是,如果 w' 只有类型 Integer 即使在单态约束下 残疾人。

    要计算出这与默认有关,请执行以下操作:

    fromFloat :: RealFrac a => Float -> a
    q :: RealFrac a => a
    q = fromFloat q
    q' = fromFloat q'
    
    GHCi> :t q
    q :: RealFrac a => a
    GHCi> :t q'
    q' :: Float

    为什么不推断多态类型?

    0 回复  |  直到 5 年前
        1
  •  19
  •   dfeuer    5 年前

    多态递归(函数以不同于调用它的类型调用自己) 总是 需要类型签名。完整的解释在 Section 4.4.1 哈斯克尔2010年报告:

    如果变量 f 定义时不提供相应的类型签名声明,则每次使用 f 在其自己的声明组之外(请参见 Section 4.5 )被视为具有相应的推论,或 主要的 类型。然而,为了确保类型推断仍然是可能的,定义发生,以及 f 在其声明组中,必须具有相同的单态类型(从中通过泛化获得主体类型,如中所述 Section 4.5.2 )

    后面的同一节给出了一个类型签名支持的多态递归示例。

    我的理解是,在存在多态递归的情况下,独立类型推理通常是不可确定的,因此Haskell甚至不尝试。

    在这种情况下,类型检查器从

    w :: a
    

    在哪里? a 是一个元变量。自从 fromInteger 被调用 w 作为其声明中的参数(因此在其声明组中),类型检查器将 具有 Integer . 没有可归纳的变量。

    对程序进行细微修改会产生不同的结果,原因相同:

    v = fromIntegral v
    

    根据你最初的推理,哈斯克尔会推断 v :: forall a. Num a => a ,默认 v 在RHS上键入 整数 :

    v :: forall a. Num a => a
    v = fromIntegral (v :: Integer)
    

    但是,它开始于 v :: a . 自从 V 传递给 fromIntegral 它强加 Integral a . 最后,它概括了 . 最后,程序被证明是

    v :: forall a. Integral a => a
    v = fromIntegral (v :: a)