Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
按需呼叫:何时在Haskell中使用?_Haskell_Lazy Evaluation - Fatal编程技术网

按需呼叫:何时在Haskell中使用?

按需呼叫:何时在Haskell中使用?,haskell,lazy-evaluation,Haskell,Lazy Evaluation,说: “按需调用是按名称调用的一种记忆版本,如果对函数参数求值,该值将被存储以供后续使用。[…]Haskell是使用按需调用求值的最著名的语言。” 然而,计算的值并不总是存储用于更快的访问(例如考虑斐波那契数的递归定义)。我在#haskell上询问了某人,答案是“仅在一个实例中,例如,如果您有‘let foo=bar baz’,foo将被评估一次”,该备忘录会自动完成 我的问题是:instance到底意味着什么?除了let之外,还有其他自动执行记忆的情况吗?haskell语言定义没有定义调用代码

说:
“按需调用是按名称调用的一种记忆版本,如果对函数参数求值,该值将被存储以供后续使用。[…]Haskell是使用按需调用求值的最著名的语言。”

然而,计算的值并不总是存储用于更快的访问(例如考虑斐波那契数的递归定义)。我在#haskell上询问了某人,答案是“仅在一个实例中,例如,如果您有‘let foo=bar baz’,foo将被评估一次”,该备忘录会自动完成


我的问题是:instance到底意味着什么?除了let之外,还有其他自动执行记忆的情况吗?

haskell语言定义没有定义调用代码的时间或频率。无限循环是根据“底部”(书面形式)定义的⊥), 这是一个表示错误条件的值(存在于所有类型中)。只要程序(以及是否存在错误条件,包括无限循环!)按照规范运行,编译器就可以自由决定何时和多久评估一次

也就是说,通常的方法是大多数表达式生成“thunks”——基本上是指向某些代码和上下文数据的指针,thunk被“强制”;指向的代码被执行,thunk被真实数据覆盖。这反过来可以递归地计算其他thunk


当然,一直这样做是很慢的,因此编译器通常会尝试分析什么时候你会立即强制执行thunk(即,当某些内容对所讨论的值“严格”时),如果它发现了这一点,它将跳过整个thunk过程并立即调用代码。如果它不能证明这一点,它仍然可以进行优化,只要它确保立即执行thunk不会崩溃或导致无限循环(或者它以某种方式处理这些条件).

如果你不想在这方面变得非常专业,关键的一点是,当你有一个表达式,比如
对所有这些参数进行一些昂贵的计算时,你可以用它做任何你想做的事情;将它存储在一个数据结构中,创建一个包含53个副本的列表,将它传递给其他6个函数,等等,然后再重新执行把它交给你的来电者,让来电者想用它做什么就做什么


Haskell将(主要)做的是最多对它求值一次;如果程序需要知道该表达式返回的内容才能做出决策,那么它将被求值(至少足以知道决策应该走哪条路)。该求值将影响对同一表达式的所有其他引用,即使它们现在分散在整个程序的数据结构和其他尚未求值的表达式中。

将此行为描述为“记忆化”是误导性的。“按调用需要”“这仅仅意味着函数的给定输入将在0到1之间的某个位置求值,而不会超过一次。(也可以部分求值,这意味着函数只需要该输入的一部分。)相反,“通过调用name”是简单的表达式替换,这意味着如果将表达式
2+3
作为函数的输入,如果输入被多次使用,则可能会多次求值。按需调用和按名称调用都是非严格的:如果不使用输入,则永远不会求值。大多数编程语言都是严格的,并且使用“按值调用”方法,这意味着无论是否使用输入,在开始计算函数之前都要计算所有输入。这一切与let表达式无关

Haskell不执行任何自动记忆。。Let表达式不是记忆的示例。但是,大多数编译器都会以按需调用的方式评估Let绑定。如果将Let表达式建模为函数,则“按需调用”的思维方式确实适用:


这并不能正确地建模递归绑定,但你明白了。

是否有不清楚是否会进行记忆的情况?只是想知道。@byrondrossos否,GHC一般或类似的情况,它可能会产生负面影响(例如,如果你仅仅因为某个未经评估的thunk使用了它的
头部,而让一个十亿元素列表保持活动状态,那么空间就会泄漏。)@delnan感谢链接,删除了我的评论,这样就不会让人困惑。
let foo = expression one in expression two that uses foo
==>
(\foo -> expression two that uses foo) (expression one)