【问题标题】:Haskell Semantics call by name / valueHaskell Semantics 按名称/值调用
【发布时间】:2020-08-19 09:42:25
【问题描述】:

我是 Haskell 的新手,我有一个问题

h x = x : (h x)
g xs = [head xs, head xs - 1]

假设语义是按名称调用和按值调用,运行 g(h 2) 的结果是什么?

【问题讨论】:

  • g (h 2) = [2,1].
  • 结果将是[2, 1],您可以通过在 GHCi 中运行它来轻松验证。 “按名称调用”与“按值调用”在 Haskell 中并没有真正的区别,因为默认情况下值是不可变的,只有可变值才有意义。
  • 这就是我混淆的原因,我知道其中一个是 [2,1],另一个可以是 [2,1 ..] 或无限循环。这就是为什么我不确定
  • Haskell 处理不可变数据,因此无法“更改”变量的值,因此您无法更新值并调用函数并期望结果会/不会发生变化。跨度>
  • 你为什么认为它在这里[2,1,...]?请注意,Haskell 使用惰性编程,这是一个在“调用风格”上“正交”的概念。

标签: haskell semantics evaluation call-by-value callbyname


【解决方案1】:

让我们一步一步走吧。

首先,h x = x : (h x) 是递归的。函数h 是根据自身定义的:给定一些x,它会将其置于list 上,即x : x : x : ... 无穷大。换句话说,由于递归永远不会终止,因此列表不可能是有限的。然而它不会永远挂起。为什么?

因为 Haskell 很懒惰。除非绝对必要,否则它不会评估任何表达式。在您的情况下,如果调用h 2,则根本不会在内存中创建无限列表。为什么?

因为g 只请求名为xs 的给定列表的前两个元素。 Haskell 足够聪明,可以根据需要扩展无限列表,而不是浪费资源。一般来说,这就是懒惰的好处。它也适用于其他表达式,而不仅仅是列表。

【讨论】:

【解决方案2】:

“按名称调用”是非记忆非严格评估策略,其中参数的值只需要在实际使用时找到内部 函数的主体,每次都是新的:

h x = x : (h x)
g xs = [head xs, head xs - 1]

g (h 2) = let {xs = (h 2)} in [head xs, head xs - 1]
        = [let {xs = (h 2)} in head xs, let {xs = (h 2)} in head xs - 1]
        = [head (h 2),                  let {xs = (h 2)} in head xs - 1]
        = [head (let {x = 2} in x : (h x)}), let {xs = (h 2)} in head xs - 1]
        = [let {x = 2} in x,            let {xs = (h 2)} in head xs - 1]
        = [2,                           let {xs = (h 2)} in head xs - 1]
        = ....

“按需调用”是记忆非严格的又名“惰性”评估策略,其中参数的值仅在函数体内使用时才需要找到第一次,然后可供进一步参考:

h x = x : (h x)
g xs = [head xs, head xs - 1]

g (h 2) = let {xs = (h 2)}       in [head xs, head xs - 1]
        = let {xs = (2 : (h 2))} in [head xs, head xs - 1]
        = let {xs = (2 : (h 2))} in [2,       head xs - 1]
        = ....

“按值调用”是严格的评估策略,其中参数的值必须在进入函数体之前找到:

h x = x : (h x)
g xs = [head xs, head xs - 1]

g (h 2) = let {xs = (h 2)} in [head xs, head xs - 1]
        = let {xs = (2 : (h 2))} in [head xs, head xs - 1]
        = let {xs = (2 : (2 : (h 2)))} in [head xs, head xs - 1]
        = let {xs = (2 : (2 : (2 : (h 2))))} in [head xs, head xs - 1]
        = ....

以上所有假设 g (h 2) 是在 GHCi 提示符下输入的,因此需要由它完整打印。

【讨论】:

    猜你喜欢
    • 2015-06-07
    • 1970-01-01
    • 2013-12-15
    • 2017-02-07
    • 1970-01-01
    • 2013-10-02
    • 2019-10-19
    • 2012-09-28
    • 2021-09-11
    相关资源
    最近更新 更多