Haskell 什么是哈斯克尔';什么是严格点?

Haskell 什么是哈斯克尔';什么是严格点?,haskell,language-design,lazy-evaluation,strictness,Haskell,Language Design,Lazy Evaluation,Strictness,我们都知道(或者应该知道)Haskell在默认情况下是懒惰的。在必须对其进行评估之前,不会对任何内容进行评估。那么什么时候必须对某些东西进行评估呢?Haskell在某些方面必须严格。我称之为“严格点”,尽管这个特殊的术语并不像我想象的那样广泛。据我说: Haskell的减少(或评估)仅发生在狭窄点 所以问题是:哈斯凯尔的严格点到底是什么?我的直觉告诉我,main、seq/bang模式、模式匹配以及通过main执行的任何IO操作都是主要的严格点,但我真的不知道为什么我知道 (同样,如果它们不是“严

我们都知道(或者应该知道)Haskell在默认情况下是懒惰的。在必须对其进行评估之前,不会对任何内容进行评估。那么什么时候必须对某些东西进行评估呢?Haskell在某些方面必须严格。我称之为“严格点”,尽管这个特殊的术语并不像我想象的那样广泛。据我说:

Haskell的减少(或评估)仅发生在狭窄点

所以问题是:哈斯凯尔的严格点到底是什么?我的直觉告诉我,
main
seq
/bang模式、模式匹配以及通过
main
执行的任何
IO
操作都是主要的严格点,但我真的不知道为什么我知道

(同样,如果它们不是“严格点”,它们叫什么?)

我想一个好的答案将包括一些关于WHNF等的讨论。我还认为它可能涉及到lambda微积分


编辑:关于这个问题的其他想法

正如我在这个问题上所思考的那样,我认为在严格点的定义中添加一些东西会更清楚。严格程度点可以具有不同的上下文和不同的深度(或严格程度)。回到我的定义“Haskell的缩减仅发生在严格点”,让我们在该定义中添加以下条款:“严格点仅在其周围环境被评估或缩减时触发。”

所以,让我试着让你开始我想要的答案
main
是一个严格点。它被特别指定为其上下文的主要严格点:程序。当程序(
main
的上下文)被评估时,main的严格性点被激活。干管深度最大:必须对其进行全面评估。Main通常由IO操作组成,这些操作也是严格点,其上下文是
Main


现在您可以尝试:用这些术语讨论
seq
和模式匹配。解释函数应用的细微差别:它是如何严格的?怎么不是呢?那么
deepseq
呢<代码>let和
case
语句<代码>不安全性能<代码>调试.跟踪?顶级定义?严格的数据类型?爆炸模式?等等。这些项目中有多少可以仅用seq或模式匹配来描述?

Haskell不是一种纯粹的惰性语言,而是一种非严格的语言。这意味着它不一定在最后一刻评估术语

哈斯克尔的“懒散”模型的一个很好的来源可以在这里找到:

基本上,理解thunk和弱头标准形式WHNF之间的区别是很重要的

我的理解是,与命令式语言相比,haskell向后拉动计算。这意味着在没有“seq”和bang模式的情况下,最终会产生某种副作用,迫使对thunk进行评估,这可能会导致之前的评估(真正的懒散)

由于这将导致可怕的空间泄漏,编译器随后会找出如何以及何时提前评估thunks以节省空间。然后,程序员可以通过提供严格注释(en.wikibooks.org/wiki/Haskell/strictness,www.Haskell.org/haskellwiki/Performance/strictness)来支持此过程,以进一步减少嵌套thunk形式的空间使用

我不是haskell操作语义方面的专家,所以我将把链接作为一种资源保留下来

更多资源:


我可能会将这个问题改写为,在什么情况下Haskell会对表达式求值?(也许加上一个“到弱头范式”。)

对于第一近似值,我们可以指定如下:

  • 执行IO操作将计算它们“需要”的任何表达式。(因此,您需要知道是否执行了IO操作,例如,它的名称是main,或者它是从main调用的,并且您需要知道该操作需要什么。)
  • 正在求值的表达式(嘿,这是一个递归定义!)将求值它需要的任何表达式
从直观的列表中,主操作和IO操作属于第一类,顺序和模式匹配属于第二类。但我认为第一类更符合您的“严格点”理念,因为事实上,这就是我们如何使Haskell中的评估成为用户可以观察到的效果


具体给出所有细节是一项艰巨的任务,因为Haskell是一种大型语言。这也是相当微妙的,因为并发Haskell可能会推测性地评估事物,即使我们最终没有使用结果:这是导致评估的第三类事物。第二类已经被很好地研究过了:您想看看所涉及的函数的严格性。第一类也可以被认为是一种“严格”,尽管这有点狡猾,因为
evaluate x
seq x$return()
实际上是不同的东西!如果给IO monad赋予某种语义(显式地传递
RealWorld
令牌适用于简单情况),您可以正确地处理它,但我不知道这种分层严格性分析是否有一个通用的名称。

懒惰并不意味着什么都不做。每当您的程序模式匹配一个
case
表达式时,它都会计算某个值——不管怎样,这已经足够了。否则,它无法确定要使用哪个RHS。在代码中看不到任何大小写表达式?别担心,编译器正在将您的代码转换为Haskell的精简形式,在这种形式下,很难避免使用它们

对于初学者来说,一个基本的经验法则是:
let
是懒惰的,
case
不那么懒惰。

C的概念是,这是对特定操作的保证,一个操作数将在另一个操作数之前求值。我认为这是最接近的存在