This question already has an answer here:
What is the monomorphism restriction?

(1个答案)


5年前关闭。




Haskell中的类型推断有一点学习曲线(至少可以说!)。一个简单的例子是开始学习它的一个好方法。因此,以下是类型推断的“hello world”。

考虑以下示例:
Prelude> :t 3
3 :: (Num t) => t
Prelude> let x = 3
Prelude> :t x
x :: Integer

因此,问题是:为什么3和x具有不同的类型?

链接摘要:

阅读以下答案以获取全文;这只是一个链接摘要:
  • GHC类型默认值:Haskell Report section4.3.4
  • GHCi的扩展类型默认值:Using GHCi section2.4.5
  • 单态限制:Haskellwiki
  • 最佳答案

    acfoltzer包含的一些链接中提到了这里的另一个因素,但是可能值得在这里明确说明。您正在遇到monomorphism restriction的影响。当你说

    let x = 5
    

    您可以对变量进行顶级定义。 MR坚持认为,这样的定义在没有类型签名的情况下应通过为未解析的类型变量选择(希望)合适的默认实例而专门化为单态值。相反,当您使用:t要求推断的类型时,则不会施加此类限制或默认设置。所以
    > :t 3
    3 :: (Num t) => t
    

    因为3确实超载了:任何数字类型都可以使用它。默认规则选择Integer作为默认数字类型,因此
    > let x = 3
    > :t x
    x :: Integer
    

    但是现在让我们关闭MR。
    > :set -XNoMonomorphismRestriction
    > let y = 3
    > :t y
    y :: (Num t) => t
    

    没有MR,该定义将尽可能多态,就像3一样重载。只是检查...
    > :t y * (2.5 :: Float)
    y * (2.5 :: Float) :: Float
    > :t y * (3 :: Int)
    y * (3 :: Int) :: Int
    

    请注意,根据相关y = 3实例随附的fromInteger方法,多态Num在这些用途中的使用方式有所不同。也就是说,y不与3的特定表示关联,而是与构造3的表示的方案关联。天真地汇编,这是缓慢的秘诀,一些人认为这是MR的动机。

    我(在本地假装)在关于单态性限制是小恶魔还是大恶魔的辩论中保持中立。我总是为顶级定义编写类型签名,因此我要实现的目标没有歧义,而MR恰恰相反。

    在尝试了解类型系统如何工作时,将类型推断的各个方面分开非常有用。
  • “遵循计划”,专门针对特定用例进行多态定义:一个相当健壮的约束解决问题,需要通过反向链进行基本统一和实例解析;和
  • “猜测计划”,对类型进行泛化以将多态类型方案分配给没有类型签名的定义:这非常脆弱,您越是越过基本的Hindley-Milner学科,具有类型类且具有较高等级的多态性,有了GADT,陌生的事物就变成了。

  • 最好学习第一个的工作原理,并理解第二个为什么很难的原因。类型推断中的许多怪异现象与第二种现象有关,并且与启发式方法(如单态性限制)有关,这种尝试试图在模棱两可的情况下提供有用的默认行为。

    关于haskell - 为什么3和x(分配给3)在Haskell中具有不同的推断类型? ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7055146/

    10-11 23:09
    查看更多