了解Haskell中的惰性求值

Ran*_*Rag 7 haskell functional-programming lazy-evaluation

我正在努力学习Haskell,但我仍然坚持理解 lazy evaluation.有人可以详细解释我的懒惰评估和以下两个案例的输出[与解释]有关下面给出的

伪代码:

x = keyboard input (5)
y = x + 3 (=8)
echo y (8)
x = keyboard input (2)
echo y
Run Code Online (Sandbox Code Playgroud)

案例1:静态绑定,懒惰评估

案例2:动态绑定,懒惰评估.

echo y在上面的两种情况下,我需要知道最后一行()将要打印的内容.

Owe*_*wen 10

对不起,这太长了,但......

我担心答案很大程度上取决于词语的含义......

首先,这是Haskell中的代码(使用静态绑定和延迟评估):

readInt :: String -> Int
readInt = read

main = do
    x <- fmap readInt getLine
    let y = x + 3
    print y
    x <- fmap readInt getLine
    print y
Run Code Online (Sandbox Code Playgroud)

它打印88.

现在这里是R中使用延迟评估的代码以及一些人称之为动态绑定的代码:

delayedAssign('x', as.numeric(readLines(n=1)))
delayedAssign('y', x + 3)
print(y)

delayedAssign('x', as.numeric(readLines(n=1)))
print(y)
Run Code Online (Sandbox Code Playgroud)

它打印88.没那么不同!

现在在C++中,它使用严格的评估和静态绑定:

#include <iostream>

int main() {
    int x;
    std::cin >> x;
    int y = x + 3;
    std::cout << y << "\n";
    std::cin >> x;
    std::cout << y << "\n";
}
Run Code Online (Sandbox Code Playgroud)

它打印88.

现在让我告诉你我认为问题的实际意义是什么;)

"懒惰的评价"可能意味着许多不同的东西.在Haskell中它有一个非常特殊的含义,即在嵌套表达式中:

f (g (h x))
Run Code Online (Sandbox Code Playgroud)

评估工作就像之前f得到评估一样 g (h x),即评估进入"外部 - >进入".实际上这意味着如果f看起来像

f x = 2
Run Code Online (Sandbox Code Playgroud)

即只是扔掉它的论点,g (h x)永远不会被评估.

但我认为这不是 "懒惰评估"的问题所在.我认为这是因为:

  • +总是评估它的论点!+无论你是否使用懒惰评估都是一样的.

  • 实际上可以延迟的唯一计算是keyboard input- 并且这不是真正的计算,因为它会导致一个动作发生; 也就是说,它从用户那里读取.

Haskell人通常不会称之为"懒惰评估" - 他们会称之为懒惰(或延迟)执行.

那么懒惰的执行对你的问题意味着什么呢?这意味着 行动 keyboard input会延迟......直到x真正需要这个价值.它看起来像这样发生在这里:

echo y
Run Code Online (Sandbox Code Playgroud)

因为在那时你必须向用户显示一个值,所以你必须知道x是什么!那么懒惰执行和静态绑定会发生什么?

x = keyboard input     # nothing happens
y = x + 3              # still nothing happens!
echo y (8)             # y becomes 8. 8 gets printed.
x = keyboard input (2) # nothing happens
echo y                 # y is still 8. 8 gets printed.
Run Code Online (Sandbox Code Playgroud)

现在关于这个词"动态绑定".它可能意味着不同的东西:

  1. 可变范围和生命周期在运行时决定.这就是像R这样的语言没有声明变量.

  2. 在计算变量之前,不会检查计算公式(如yis 的公式x + 3).

我的猜测是,"动态绑定"在你的问题中意味着什么.使用动态绑定(sense 2)和延迟执行再次遍历代码:

x = keyboard input     # nothing happens
y = x + 3              # still nothing happens!
echo y (8)             # y becomes 8. 8 gets printed.
x = keyboard input (2) # nothing happens
echo y                 # y is already evaluated, 
                       # so it uses the stored value and prints 8
Run Code Online (Sandbox Code Playgroud)

我知道没有任何语言可以打印7到最后一行...但我真的认为这就是希望会发生的问题!

  • @RanRag:正如Owen指出的那样,你将lazy*evaluation*与延迟*执行*混淆.正如[Learn You a Haskell](http://learnyouahaskell.com/introduction)的介绍所说:"你也不能将变量设置为某个东西,然后将其设置为其他东西.如果你说'a `是5,你不能说以后别的什么,因为你刚才说它是5.你是什么,某种骗子? - 关键是,你说'x =键盘输入' - 意思是"这个键盘输入就在这里".它不会成为"稍后发生的某些键盘输入" - 这将是谎言! (2认同)