非严格和惰性有何不同?

发布于 2024-11-30 23:16:54 字数 3994 浏览 5 评论 0原文

我经常读到惰性非严格不同,但我发现很难理解其中的区别。它们似乎可以互换使用,但我知道它们有不同的含义。我希望能得到一些帮助来理解其中的差异。

我有几个关于这篇文章的问题。我将在本文末尾总结这些问题。我有一些示例片段,我没有测试它们,我只是将它们作为概念呈现。我添加了引号,以免您查找它们。也许它会对以后遇到同样问题的人有所帮助。

非严格定义:

函数 f 被称为严格函数,如果应用于非终止函数 表达式,它也无法终止。换句话说,f 是严格的 当且仅当 f bot 的值为 |。对于大多数编程语言来说,所有 功能是严格的。但在 Haskell 中却并非如此。作为一个简单的 例如,考虑 const1,常量 1 函数,定义为:

const1 x = 1

Haskell 中 const1 bot 的值为 1。从操作上来说,因为 const1 并不“需要”其参数的值,它从不尝试 评估它,因此永远不会陷入无休止的困境 计算。因此,非严格函数也称为 “惰性函数”,据说会“惰性地”评估它们的参数, 或“根据需要”。

-Haskell 简介:函数

我真的很喜欢这个定义。这似乎是我能找到的最好的理解严格的方法。 const1 x = 1 也是懒惰的吗?

非严格性意味着减少(数学术语 评估)从外到内的收益,

所以如果你有 (a+(bc)) 那么首先你减少 +,然后你减少 内部 (bc)。

-Haskell Wiki:惰性 vs 非严格

Haskell Wiki 真的让我很困惑。我理解他们所说的关于顺序的内容,但我不明白如果通过 _|_(a+(b*c)) 将如何非严格地评估?

在非严格求值中,不求值函数的参数 除非它们实际用于函数体的求值。

在 Church 编码下,运算符的惰性求值映射到非严格 功能评估;因此,非严格评估是 通常被称为“懒惰”。许多语言都使用布尔表达式 一种称为短路评估的非严格评估形式,其中 一旦可以确定明确的评估返回 将产生布尔值 - 例如,在析取表达式中,其中 遇到 true 或在连接表达式中遇到 false 时 遇到过等等。条件表达式也通常使用 惰性求值,一旦得到明确的结果,求值立即返回 将产生分支。

-维基百科:评估策略

惰性定义:

另一方面,惰性评估意味着仅评估 需要其结果时的表达式(注意从 “减少”为“评估”)。因此,当评估引擎看到 表达式它构建一个包含任何值的 thunk 数据结构 需要计算表达式,加上一个指向 表达本身。当实际需要结果时进行评估 引擎调用表达式,然后用 thunk 替换 结果供将来参考。 ...

显然 thunk 和 a 之间有很强的对应关系 部分评估的表达式。因此,在大多数情况下,术语“惰性”和 “非严格”是同义词。但也不完全是。

-Haskell Wiki:惰性与非严格

这似乎是 Haskell 的具体答案。我认为惰性意味着thunk,非严格意味着部分评估。这样的比较是不是太简单化了? lazy 是否总是意味着 thunk,而 non-strict 总是意味着部分评估。

在编程语言理论中,惰性求值或按需调用1 是 延迟表达式求值的求值策略 直到实际需要它的值(非严格评估)并且 避免重复评估(共享)。

-维基百科:惰性求值

命令式示例

我知道大多数人都说在学习函数式语言时忘记命令式编程。但是,我想知道这些是否符合非严格、惰性、两者或两者都没有的资格?至少它会提供一些熟悉的东西。

短路

f1() || f2()

C#、Python 和其他有“yield”的语言

public static IEnumerable Power(int number, int exponent)
{
    int counter = 0;
    int result = 1;
    while (counter++ < exponent)
    {
        result = result * number;
        yield return result;
    }
}

-MSDN:yield (c#)

回调

int f1() { return 1;}
int f2() { return 2;}

int lazy(int (*cb1)(), int (*cb2)() , int x) {
    if (x == 0)
        return cb1();
    else
        return cb2();
}

int eager(int e1, int e2, int x) {
    if (x == 0)
         return e1;
    else
         return e2;
}

lazy(f1, f2, x);
eager(f1(), f2(), x);

问题

我知道答案是正确的 这么多资源摆在我面前,但我无法掌握。看起来这个定义很容易被认为是隐含的或明显的而被忽视。

我知道我有很多问题。请随意回答您认为相关的任何问题。我添加了这些问题以供讨论。

  • const1 x = 1 也是懒惰的吗?
  • 从“内部”评估如何是非严格的?是因为 inward 允许减少不必要的表达式,比如 const1 x = 1 吗?减少似乎符合懒惰的定义。
  • 惰性是否总是意味着thunks,而非严格总是意味着部分评估?这只是一个概括吗?
  • 以下命令式概念是惰性的、非严格的、两者都是还是两者都不是?
    • 短路
    • 使用产量
    • 传递回调以延迟或避免执行
  • 惰性非严格的子集,反之亦然,或者它们是互斥的。例如,是否可以做到非严格而不懒惰,或者懒惰而不非严格
  • Haskell 的不严格是通过懒惰实现的吗?

谢谢你!

I often read that lazy is not the same as non-strict but I find it hard to understand the difference. They seem to be used interchangeably but I understand that they have different meanings. I would appreciate some help understanding the difference.

I have a few questions which are scattered about this post. I will summarize those questions at the end of this post. I have a few example snippets, I did not test them, I only presented them as concepts. I have added quotes to save you from looking them up. Maybe it will help someone later on with the same question.

Non-Strict Def:

A function f is said to be strict if, when applied to a nonterminating
expression, it also fails to terminate. In other words, f is strict
iff the value of f bot is |. For most programming languages, all
functions are strict. But this is not so in Haskell. As a simple
example, consider const1, the constant 1 function, defined by:

const1 x = 1

The value of const1 bot in Haskell is 1. Operationally speaking, since
const1 does not "need" the value of its argument, it never attempts to
evaluate it, and thus never gets caught in a nonterminating
computation. For this reason, non-strict functions are also called
"lazy functions", and are said to evaluate their arguments "lazily",
or "by need".

-A Gentle Introduction To Haskell: Functions

I really like this definition. It seems the best one I could find for understanding strict. Is const1 x = 1 lazy as well?

Non-strictness means that reduction (the mathematical term for
evaluation) proceeds from the outside in,

so if you have (a+(bc)) then first you reduce the +, then you reduce
the inner (b
c).

-Haskell Wiki: Lazy vs non-strict

The Haskell Wiki really confuses me. I understand what they are saying about order but I fail to see how (a+(b*c)) would evaluate non-strictly if it was pass _|_?

In non-strict evaluation, arguments to a function are not evaluated
unless they are actually used in the evaluation of the function body.

Under Church encoding, lazy evaluation of operators maps to non-strict
evaluation of functions; for this reason, non-strict evaluation is
often referred to as "lazy". Boolean expressions in many languages use
a form of non-strict evaluation called short-circuit evaluation, where
evaluation returns as soon as it can be determined that an unambiguous
Boolean will result — for example, in a disjunctive expression where
true is encountered, or in a conjunctive expression where false is
encountered, and so forth. Conditional expressions also usually use
lazy evaluation, where evaluation returns as soon as an unambiguous
branch will result.

-Wikipedia: Evaluation Strategy

Lazy Def:

Lazy evaluation, on the other hand, means only evaluating an
expression when its results are needed (note the shift from
"reduction" to "evaluation"). So when the evaluation engine sees an
expression it builds a thunk data structure containing whatever values
are needed to evaluate the expression, plus a pointer to the
expression itself. When the result is actually needed the evaluation
engine calls the expression and then replaces the thunk with the
result for future reference.
...

Obviously there is a strong correspondence between a thunk and a
partly-evaluated expression. Hence in most cases the terms "lazy" and
"non-strict" are synonyms. But not quite.

-Haskell Wiki: Lazy vs non-strict

This seems like a Haskell specific answer. I take that lazy means thunks and non-strict means partial evaluation. Is that comparison too simplified? Does lazy always mean thunks and non-strict always mean partial evaluation.

In programming language theory, lazy evaluation or call-by-need1 is
an evaluation strategy which delays the evaluation of an expression
until its value is actually required (non-strict evaluation) and also
avoid repeated evaluations (sharing).

-Wikipedia: Lazy Evaluation

Imperative Examples

I know most people say forget imperative programming when learning a functional language. However, I would like to know if these qualify as non-strict, lazy, both or neither? At the very least it would provide something familiar.

Short Circuiting

f1() || f2()

C#, Python and other languages with "yield"

public static IEnumerable Power(int number, int exponent)
{
    int counter = 0;
    int result = 1;
    while (counter++ < exponent)
    {
        result = result * number;
        yield return result;
    }
}

-MSDN: yield (c#)

Callbacks

int f1() { return 1;}
int f2() { return 2;}

int lazy(int (*cb1)(), int (*cb2)() , int x) {
    if (x == 0)
        return cb1();
    else
        return cb2();
}

int eager(int e1, int e2, int x) {
    if (x == 0)
         return e1;
    else
         return e2;
}

lazy(f1, f2, x);
eager(f1(), f2(), x);

Questions

I know the answer is right in front of me with all those resources, but I can't grasp it. It all seems like the definition is too easily dismissed as implied or obvious.

I know I have a lot of questions. Feel free to answer whatever questions you feel are relevant. I added those questions for discussion.

  • Is const1 x = 1 also lazy?
  • How is evaluating from "inward" non-strict? Is it because inward allows reductions of unnecessary expressions, like in const1 x = 1? Reductions seem to fit the definition of lazy.
  • Does lazy always mean thunks and non-strict always mean partial evaluation? Is this just a generalization?
  • Are the following imperative concepts Lazy, Non-Strict, Both or Neither?
    • Short Circuiting
    • Using yield
    • Passing Callbacks to delay or avoid execution
  • Is lazy a subset of non-strict or vice versa, or are they mutually exclusive. For example is it possible to be non-strict without being lazy, or lazy without being non-strict?
  • Is Haskell's non-strictness achieved by laziness?

Thank you SO!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

○闲身 2024-12-07 23:16:54

非严格和惰性虽然非正式地可以互换,但适用于不同的讨论领域。

非严格语义:表达式的数学含义。非严格适用的世界没有函数的运行时间、内存消耗甚至计算机的概念。它只是讨论域中的哪些类型的值映射到共域中的哪些类型的值。特别是,严格函数必须将值 ⊥(“bottom”——有关更多信息,请参阅上面的语义链接)映射到 ⊥;允许非严格函数不这样做。

惰性指的是操作行为:代码在真实计算机上执行的方式。大多数程序员都从操作角度考虑程序,所以这可能就是您的想法。惰性求值是指使用 thunk 的实现——指向代码的指针,这些代码在第一次执行时被值替换。注意这里的非语义词:“指针”、“第一次”、“执行”。

惰性求值会产生不严格的语义,这就是为什么这些概念看起来如此接近。但正如 FUZxxl 指出的那样,惰性并不是实现非严格语义的唯一方法。

如果您有兴趣了解有关此区别的更多信息,我强烈推荐上面的链接。阅读这本书是我对计算机程序含义概念的转折点。

Non-strict and lazy, while informally interchangeable, apply to different domains of discussion.

Non-strict refers to semantics: the mathematical meaning of an expression. The world to which non-strict applies has no concept of the running time of a function, memory consumption, or even a computer. It simply talks about what kinds of values in the domain map to which kinds of values in the codomain. In particular, a strict function must map the value ⊥ ("bottom" -- see the semantics link above for more about this) to ⊥; a non strict function is allowed not to do this.

Lazy refers to operational behavior: the way code is executed on a real computer. Most programmers think of programs operationally, so this is probably what you are thinking. Lazy evaluation refers to implementation using thunks -- pointers to code which are replaced with a value the first time they are executed. Notice the non-semantic words here: "pointer", "first time", "executed".

Lazy evaluation gives rise to non-strict semantics, which is why the concepts seem so close together. But as FUZxxl points out, laziness is not the only way to implement non-strict semantics.

If you are interested in learning more about this distinction, I highly recommend the link above. Reading it was a turning point in my conception of the meaning of computer programs.

天涯沦落人 2024-12-07 23:16:54

评估模型的一个示例,既不是严格也不是惰性:乐观评估,它提供了一些加速,因为它可以避免很多“简单”谢谢:

乐观评估意味着即使可能不需要子表达式来评估超表达式,我们仍然使用一些启发式评估其中的一些。如果子表达式没有足够快地终止,我们将暂停其计算,直到真正需要它为止。如果稍后需要子表达式,这给我们带来了优于惰性求值的优势,因为我们不需要生成 thunk。另一方面,如果表达式没有终止,我们也不会损失太多,因为我们可以足够快地中止它。

正如您所看到的,此评估模型并不严格:如果对产生 _|_ 的内容进行了评估,但不需要,则该函数仍将终止,因为引擎会中止评估。另一方面,可能会计算超出所需数量的表达式,因此它完全惰性

An example for an evaluation model, that is neither strict nor lazy: optimistic evaluation, which gives some speedup as it can avoid a lot of "easy" thunks:

Optimistic evaluation means that even if a subexpression may not be needed to evaluate the superexpression, we still evaluate some of it using some heuristics. If the subexpression doesn't terminate quickly enough, we suspend its evaluation until it's really needed. This gives us an advantage over lazy evaluation if the subexpression is needed later, as we don't need to generate a thunk. On the other hand, we don't lose too much if the expression doesn't terminate, as we can abort it quickly enough.

As you can see, this evaluation model is not strict: If something that yields _|_ is evaluated, but not needed, the function will still terminate, as the engine aborts the evaluation. On the other hand, it may be possible that more expressions than needed are evaluated, so it's not completely lazy.

半世晨晓 2024-12-07 23:16:54

是的,这里有一些术语的使用不清楚,但无论如何,这些术语在大多数情况下都是一致的,所以这不是什么太大的问题。

一个主要区别在于评估条款的时间。对此有多种策略,范围从“尽快”到“仅在最后一刻”。术语急切评估有时用于表示倾向于前者的策略,而惰性评估则正确地指代一系列严重倾向于后者的策略。 “惰性评估”和相关策略之间的区别往往涉及评估某物的结果何时何地被保留,而不是被扔到一边。 Haskell 中为数据结构分配名称并为其建立索引的熟悉的记忆技术就是基于此。相反,简单地将表达式相互拼接的语言(如“按名称调用”计算)可能不支持这一点。

另一个区别是评估哪些术语,范围从“绝对所有”到“尽可能少”。由于实际用于计算最终结果的任何值都不能被忽略,因此这里的区别在于评估了多少多余的项。除了减少程序必须完成的工作量之外,忽略未使用的术语还意味着它们不会产生任何错误。当进行区分时,严格性指的是评估所考虑的所有事物的属性(例如,在严格函数的情况下,这意味着它所应用的术语。它确实如此) t 必然意味着参数内的子表达式),而非严格意味着仅评估某些事物(通过延迟评估或完全丢弃术语)。

应该很容易看出它们如何以复杂的方式相互作用;决策根本不是正交的,因为极端情况往往是不相容的。例如:

  • 非常不严格的评估会排除一定程度的渴望;如果您不知道某个术语是否需要,您还无法评估它。

  • 非常严格的评估使得不热心有些无关紧要;如果你正在评估一切,那么何时这样做的决定就不那么重要了。

不过,确实存在替代定义。例如,至少在 Haskell 中,“严格函数”通常被定义为一个足以强制其参数的函数,无论何时任何参数出现,该函数都会计算为 _|_ (“底部”);请注意,根据此定义,id 是严格的(在微不足道的意义上),因为强制 id x 的结果将与强制 x< 具有完全相同的行为/code> 单独。

Yes, there is some unclear use of terminology here, but the terms coincide in most cases regardless, so it's not too much of a problem.

One major difference is when terms are evaluated. There are multiple strategies for this, ranging on a spectrum from "as soon as possible" to "only at the last moment". The term eager evaluation is sometimes used for strategies leaning toward the former, while lazy evaluation properly refers to a family of strategies leaning heavily toward the latter. The distinction between "lazy evaluation" and related strategies tend to involve when and where the result of evaluating something is retained, vs. being tossed aside. The familiar memoization technique in Haskell of assigning a name to a data structure and indexing into it is based on this. In contrast, a language that simply spliced expressions into each other (as in "call-by-name" evaluation) might not support this.

The other difference is which terms are evaluated, ranging from "absolutely everything" to "as little as possible". Since any value actually used to compute the final result can't be ignored, the difference here is how many superfluous terms are evaluated. As well as reducing the amount of work the program has to do, ignoring unused terms means that any errors they would have generated won't occur. When a distinction is being drawn, strictness refers to the property of evaluating everything under consideration (in the case of a strict function, for instance, this means the terms it's applied to. It doesn't necessarily mean sub-expressions inside the arguments), while non-strict means evaluating only some things (either by delaying evaluation, or by discarding terms entirely).

It should be easy to see how these interact in complicated ways; decisions are not at all orthogonal, as the extremes tend to be incompatible. For instance:

  • Very non-strict evaluation precludes some amount of eagerness; if you don't know whether a term will be needed, you can't evaluate it yet.

  • Very strict evaluation makes non-eagerness somewhat irrelevant; if you're evaluating everything, the decision of when to do so is less significant.

Alternate definitions do exist, though. For instance, at least in Haskell, a "strict function" is often defined as one that forces its arguments sufficiently that the function will evaluate to _|_ ("bottom") whenever any argument does; note that by this definition, id is strict (in a trivial sense), because forcing the result of id x will have exactly the same behavior as forcing x alone.

岛徒 2024-12-07 23:16:54

这开始是一个更新,但开始变得很长。

懒惰/按需调用是 call 的记忆版本-by-name 其中,如果对函数参数进行求值,则存储该值以供后续使用。在“纯粹”(无效果)设置中,这会产生与按名称调用相同的结果;当函数参数使用两次或多次时,按需调用几乎总是更快。
命令式示例 - 显然这是可能的。有一篇有趣的文章 惰性命令式语言。它说有两种方法。一种需要闭包,第二种使用图缩减。由于 C 不支持闭包,因此您需要显式地将参数传递给迭代器。您可以包装一个映射结构,如果该值不存在,则计算它,否则返回值。
注意:Haskell 通过“指向代码的指针在第一次执行时被值替换”来实现这一点 - luqui。
这是非严格的点名方式,但会共享/记忆结果。

按名称调用 - 在按名称调用求值中,函数的参数在调用函数之前不会求值,而是直接替换到函数体中(使用 capture -避免替代)然后每当它们出现在函数中时就对其进行评估。如果函数体中未使用参数,则永远不会计算该参数;如果多次使用,则每次出现时都会重新评估。
命令式示例:回调
注意:这是非严格的,因为如果不使用它会避免评估。

非严格 = 在非严格求值中,函数的参数不会被求值,除非它们实际用于函数体的求值。
命令式示例:短路
注意:_|_ 似乎是测试函数是否非严格的一种方法

因此函数可以是非严格的,但不能是惰性的。惰性函数始终是非严格的。
Call-By-Need 部分由 Call-By-Name 定义,而 Call-By-Name 部分由 Non-Strict

定义href="http://webcache.googleusercontent.com/search?q=cache%3ao7wQ-sooFyUJ%3aciteseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.35.1663& ;rep=rep1&type=ps%20%22call%20by%20need%22%20imperative%20language&cd=3&hl=en&ct=clnk&gl=ca&source=www.google.ca" rel="nofollow noreferrer">"惰性命令式语言"

2.1。非严格语义 VS 严格语义LAZY EVALUATION 我们必须首先澄清
“非严格语义”和“惰性求值”之间的区别。
非严格语义是那些指定表达式不是
评估直到原始操作需要它为止。可能有
各种类型的非严格语义。例如,非严格
过程调用不会评估参数,直到它们的值被确定为止
必需的。数据构造函数可能具有非严格语义,其中
复合数据是由未评估的片段组装而成的惰性评估,
也称为延迟评估,是通常用于
实施非严格语义。第 4 节中,这两种方法通常
对用于实现惰性求值的方法进行了非常简要的总结。

按值调用、惰性调用和按名称调用 “按值调用”是
用于具有严格语义的过程调用的通用名称。通话中
通过值语言,过程调用的每个参数都会被评估
在进行过程调用之前;然后将该值传递给
过程或封闭表达式。按值调用的另一个名称是
“热切”评估。按值调用也称为“应用顺序”
评估,因为所有参数都在函数执行之前评估
适用于他们。“懒惰调用”(使用 William Clinger 的术语
[8]) 是给使用非严格的过程调用的名称
语义。在通过惰性过程调用进行调用的语言中,
参数在代入过程之前不会被求值
身体。通过惰性评估进行的调用也称为“正常
order”评估,因为顺序(从最外层到最内层,左
到右边)的表达式求值。“按名称调用”是
Algol-60 [18] 中使用的惰性调用的特定实现。这
Algol-60 的设计者希望按名称调用参数
物理地替换到过程体中,用括号括起来
并在尸体被遗弃之前进行适当的名称更改以避免冲突
已评估。

懒惰呼叫与懒惰呼叫按需要呼叫 按需要呼叫是
通过懒惰的扩展调用,通过观察发现一个懒惰的提示
可以通过记住给定的值来优化评估
延迟表达,一旦强制,则该值不需要
如果再次需要则重新计算。通过需求评估来电,
因此,通过使用记忆来扩展惰性方法的调用以避免
需要反复评估。弗里德曼和怀斯就是其中之一
最早倡导需求评估的呼吁,提出“自杀式”
悬架”在首次评估时会自毁,
用他们的价值观取代他们自己。

This started out as an update but it started to get long.

Laziness / Call-by-need is a memoized version of call-by-name where, if the function argument is evaluated, that value is stored for subsequent uses. In a "pure" (effect-free) setting, this produces the same results as call-by-name; when the function argument is used two or more times, call-by-need is almost always faster.
Imperative Example - Apparently this is possible. There is an interesting article on Lazy Imperative Languages. It says there are two methods. One requires closures the second uses graph reductions. Since C does not support closures you would need to explicitly pass an argument to your iterator. You could wrap a map structure and if the value does not exist calculate it otherwise return value.
Note: Haskell implements this by "pointers to code which are replaced with a value the first time they are executed" - luqui.
This is non-strict call-by-name but with sharing/memorization of the results.

Call-By-Name - In call-by-name evaluation, the arguments to a function are not evaluated before the function is called — rather, they are substituted directly into the function body (using capture-avoiding substitution) and then left to be evaluated whenever they appear in the function. If an argument is not used in the function body, the argument is never evaluated; if it is used several times, it is re-evaluated each time it appears.
Imperative Example: callbacks
Note: This is non-strict as it avoids evaluation if not used.

Non-Strict = In non-strict evaluation, arguments to a function are not evaluated unless they are actually used in the evaluation of the function body.
Imperative Example: short-circuiting
Note: _|_ appears to be a way to test if a function is non-strict

So a function can be non-strict but not lazy. A function that is lazy is always non-strict.
Call-By-Need is partly defined by Call-By-Name which is partly defined by Non-Strict

An Excerpt from "Lazy Imperative Languages"

2.1. NON-STRICT SEMANTICS VS. LAZY EVALUATION We must first clarify
the distinction between "non-strict semantics" and "lazy evaluation".
Non-strictsemantics are those which specify that an expression is not
evaluated until it is needed by a primitiveoperation. There may be
various types of non-strict semantics. For instance, non-strict
procedure calls donot evaluate the arguments until their values are
required. Data constructors may have non-strictsemantics, in which
compound data are assembled out of unevaluated pieces Lazy evaluation,
also called delayed evaluation, is the technique normally used to
implement non-strictsemantics. In section 4, the two methods commonly
used to implement lazy evaluation are very brieflysummarized.

CALL BY VALUE, CALL BY LAZY, AND CALL BY NAME "Call by value" is the
general name used for procedure calls with strict semantics. In call
by valuelanguages, each argument to a procedure call is evaluated
before the procedure call is made; the value isthen passed to the
procedure or enclosing expression. Another name for call by value is
"eager" evaluation.Call by value is also known as "applicative order"
evaluation, because all arguments are evaluated beforethe function is
applied to them."Call by lazy" (using William Clinger's terminology in
[8]) is the name given to procedure calls which usenon-strict
semantics. In languages with call by lazy procedure calls, the
arguments are not evaluatedbefore being substituted into the procedure
body. Call by lazy evaluation is also known as "normal
order"evaluation, because of the order (outermost to innermost, left
to right) of evaluation of an expression."Call by name" is a
particular implementation of call by lazy, used in Algol-60 [18]. The
designers ofAlgol-60 intended that call-by-name parameters be
physically substituted into the procedure body, enclosedby parentheses
and with suitable name changes to avoid conflicts, before the body was
evaluated.

CALL BY LAZY VS. CALL BY NEED Call by need is an
extension of call by lazy, prompted by the observation that a lazy
evaluation could beoptimized by remembering the value of a given
delayed expression, once forced, so that the value need notbe
recalculated if it is needed again. Call by need evaluation,
therefore, extends call by lazy methods byusing memoization to avoid
the need for repeated evaluation. Friedman and Wise were among the
earliestadvocates of call by need evaluation, proposing "suicidal
suspensions" which self-destructed when theywere first evaluated,
replacing themselves with their values.

飘过的浮云 2024-12-07 23:16:54

按照我的理解,“非严格”意味着试图通过以较少的工作量完成来减少工作量。

而“惰性评估”和类似尝试通过避免完全完成(希望永远)来减少总体工作量。

从你的例子来看......

f1() || f2()

这个表达式的短路不可能导致触发“未来的工作”,并且推理中既没有投机/摊销因素,也没有任何计算复杂性债务的累积。

而在 C# 示例中,“惰性”在整体视图中保留了函数调用,但作为交换,却带来了上述各种困难(至少从调用点到可能完全完成......在这段代码中,这是一个可以忽略不计的-距离路径,但想象一下这些函数有一些高争用的锁需要忍受)。

int f1() { return 1;}
int f2() { return 2;}

int lazy(int (*cb1)(), int (*cb2)() , int x) {
    if (x == 0)
        return cb1();
    else
        return cb2();
}

int eager(int e1, int e2, int x) {
    if (x == 0)
         return e1;
    else
         return e2;
}

lazy(f1, f2, x);
eager(f1(), f2(), x);

The way I understand it, "non-strict" means trying to reduce workload by reaching completion in a lower amount of work.

Whereas "lazy evaluation" and similar try to reduce overall workload by avoiding full completion (hopefully forever).

from your examples...

f1() || f2()

...short circuiting from this expression would not possibly result in triggering 'future work', and there's neither a speculative/amortized factor to the reasoning, nor any computational complexity debt accruing.

Whereas in the C# example, "lazy" conserves a function call in the overall view, but in exchange, comes with those above sorts of difficulty (at least from point of call until possible full completion... in this code that's a negligible-distance pathway, but imagine those functions had some high-contention locks to put up with).

int f1() { return 1;}
int f2() { return 2;}

int lazy(int (*cb1)(), int (*cb2)() , int x) {
    if (x == 0)
        return cb1();
    else
        return cb2();
}

int eager(int e1, int e2, int x) {
    if (x == 0)
         return e1;
    else
         return e2;
}

lazy(f1, f2, x);
eager(f1(), f2(), x);
何以畏孤独 2024-12-07 23:16:54

如果我们谈论一般的计算机科学术语,那么“惰性”和“非严格”通常是同义词——它们代表相同的整体想法,在不同的情况下以不同的方式表达自己。

然而,在给定的特定专业背景下,它们可能具有不同的技术含义。我认为您无法准确和普遍地描述在需要做出改变的情况下“懒惰”和“非严格”之间的区别。

If we're talking general computer science jargon, then "lazy" and "non-strict" are generally synonyms -- they stand for the same overall idea, which expresses itself in different ways for different situations.

However, in a given particular specialized context, they may have acquired differing technical meanings. I don't think you can say anything accurate and universal about what the difference between "lazy" and "non-strict" is likely to be in the situation where there is a difference to make.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文