【问题标题】:How does evaluation in Haskell work, for expressions with constraintsHaskell 中的求值是如何工作的,对于有约束的表达式
【发布时间】:2020-04-01 13:14:52
【问题描述】:

假设我用 GHCi 写代码:

GHCi> let x = 1 + 2 :: Integer
GHCi> seq x ()
GHCi> :sprint x

GHCi 按自然预期打印x = 3

然而,

GHCi> let x = 1 + 2
GHCi> seq x ()
GHCi> :sprint x

收益x = _

这两个表达式之间的唯一区别是它们的类型(IntegerNum a => a)。我的问题是到底发生了什么,为什么在后一个示例中似乎没有评估 x

【问题讨论】:

    标签: haskell polymorphism evaluation strictness


    【解决方案1】:

    主要问题是

    let x = 1 + 2
    

    定义了一个forall a. Num a => a 类型的多态值,它的计算类似于函数。

    x 的每次使用都可以使用不同的类型,例如x :: Intx :: Integerx :: Double 等等。这些结果不会以任何方式“缓存”,而是每次都重新计算,就好像x 是一个被多次调用的函数一样。

    确实,类型类的常见实现将这种多态x 实现为函数

    x :: NumDict a -> a
    

    上面的NumDict a参数是编译器自动添加的,它携带了aNum类型的信息,包括如何执行加法,如何解释a中的整数文字等等.这称为“字典传递”实现。

    因此,多次使用多态x 确实对应于多次调用函数,导致重新计算。为了避免这种情况,在 Haskell 中引入了(可怕的)单态限制,迫使 x 改为单态。 MR 并不是一个完美的解决方案,并且在某些情况下会产生一些令人惊讶的类型错误。

    为了缓解这个问题,在 GHCi 中默认禁用 MR,因为在 GHCi 中我们不太关心性能 - 可用性在那里更重要。然而,正如您所发现的,这会导致重新计算重新出现。

    【讨论】:

    • 我认为值得一提的字典传递正在进行中。
    猜你喜欢
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    • 2019-09-06
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    相关资源
    最近更新 更多