代码之家  ›  专栏  ›  技术社区  ›  Tom Crockett

为什么在Haskell中不推断多态值?

  •  21
  • Tom Crockett  · 技术社区  · 14 年前

    数字文本具有多态类型:

    *Main> :t 3
    3 :: (Num t) => t
    

    但如果我将一个变量绑定到这样一个文本,多态性就会丢失:

    x = 3
    ...
    *Main> :t x
    x :: Integer
    

    另一方面,如果我定义一个函数,它当然是多态的:

    f x = 3
    ...
    *Main> :t f
    f :: (Num t1) => t -> t1
    

    我可以提供一个类型签名来确保 x 保持多态性:

    x :: Num a => a
    x = 3
    ...
    *Main> :t x
    x :: (Num a) => a
    

    但为什么这是必要的?为什么不推断多态类型?

    2 回复  |  直到 14 年前
        1
  •  23
  •   dfeuer    9 年前

    是那个 monomorphism restriction 也就是说,所有没有参数定义且没有显式类型注释的值都应该具有单形类型。在ghc和ghci中可以使用 -XNoMonomorphismRestriction .

    限制的原因是没有这个限制 long_calculation 42 将被评估两次,而大多数人可能希望/希望只评估一次:

    longCalculation :: Num a => a -> a
    longCalculation = ...
    
    x = longCalculation 42
    
    main = print $ x + x
    
        2
  •  19
  •   Community CDub    8 年前

    要稍微扩展一下sepp2k的答案:如果您尝试编译以下内容(或将其加载到GHCi中),就会得到一个错误:

    import Data.List (sort)
    f = head . sort
    

    这违反了单态限制,因为我们有一个类约束(由 sort )但没有明确的论据:我们(有些神秘)被告知 Ambiguous type variable 在约束中 Ord a .

    你的例子( let x = 3 )具有类似的不明确类型变量,但它不会给出相同的错误,因为它是由 Haskell's "defaulting" rules :

    任何单态类型变量 当 整个模块都完成了 考虑过的 模棱两可的 ,并已解决 使用 违约规则(第4.3.4节)。

    this answer 有关默认规则的更多信息,重要的一点是它们只适用于某些数值类,因此 x = 3 没事的时候 f = sort 不是。

    顺便说一句:如果你愿意的话 x=3 最终成为一个 Int 而不是 Integer ,和 y = 3.0 成为 Rational 而不是 Double ,可以使用“默认声明”覆盖默认默认规则:

    default (Int, Rational)
    
    推荐文章