【发布时间】:2014-07-25 18:48:41
【问题描述】:
我正在阅读有关 haskell 中的惰性评估的信息,并有一个问题。例如我们有以下计算:
Prelude> let x = 1 + 1 :: Int
Prelude> let y = (x,x)
得到x的值后:
Prelude> :sprint x
x = _
这是未经评估的。好的,现在让我们获取 y 的值:
Prelude> :sprint y
y = (_,_)
它也没有被评估,因为y 依赖于x and it's unevaluated。现在让我们试试同样的例子,但没有::Int:
Prelude> let x = 1 + 1
Prelude> let y = (x, x)
Prelude> :sprint y
y = _
当我们尝试不使用::Int 时,为什么y 的值是_ 而不是(_, _)?
我看到它们有不同的类型:
Prelude> let x = 1 + 1
Prelude> :t x
x :: Num a => a
Prelude> let x = 1 + 1 :: Int
Prelude> :t x
x :: Int
但是为什么y 的值取决于它呢?
谢谢。
【问题讨论】:
-
现在是真正有趣的部分,
x的类型为Num a => a,在您全面评估x和y之后会发生什么?他们的:sprint代表会怎样? -
@bheklilr,是的,非常有趣。我做了:
seq用于x和y,它们打印值,但 :sprint 打印_ -
当
x的类型是Num a => a时,它甚至意味着什么?编译器如何知道如何处理它?当它不知道要使用+的哪个实现时,它怎么能说x的值是2?我可以在Int周围实现我自己的新类型,将+定义为(MyInt x) + (MyInt y) = MyInt (x - y),那么GHC 在这里做什么才能打印x的值2? -
它不可能知道使用
Num的哪个实例来打印它,对吧?那么你认为它在做什么呢?如果您正在编写 GHCi 并希望能够打印出Num a => a类型的值,并且假设没有人会邪恶到将+定义为-,您会怎么做?我知道我只会选择一个健全的默认值来“评估”它,但实际上不会将该结果存储在变量的内存位置 -
@CarstenKönig 这发生在我的 GHC 中。如果
y :: Num a => (a, a),那么它甚至无法评估yWHNF(我认为?),所以它的thunk 是_,而不是(_, _)。你可能有MonomorphismRestriction吗?自从我将 GHCi 配置为默认禁用它以来,我还没有测试过它。