spo*_*ang 9 haskell functional-programming lazy-evaluation
在Haskell编程语言的规范规定,它是一种非严格的语言,但没有任何有关评估战略(比如何时以及如何计算一个表达式时,到什么水平).在谈论模式匹配时,它确实多次提到"评估"这个词.
我已经阅读了关于延迟评估和弱头正常形式的精彩教程,但它只是一些编译器的实现策略,在编写代码时我不应该依赖它.
我来自严格的语言背景,如果我不理解我的代码是如何执行的,我感觉不对.我想知道为什么语言规范没有定义评估策略.
我希望有人能开导我.谢谢!
我认为,在Haskell中尝试关注评估顺序会产生相反的效果.该语言不仅旨在使评估顺序无关紧要,而且评估顺序可以以奇怪和混乱的方式遍布整个地方.此外,如果最终结果仍然相同,则实现具有以不同方式执行事物的大量自由[1]或大量重构程序[2],因此可能以不同方式评估程序的不同部分.
唯一真正的限制是你不能使用的评估策略.例如,您不能总是使用严格的评估,因为这会导致有效程序崩溃或进入无限循环.
const 17 undefined
take 10 (repeat 17)
Run Code Online (Sandbox Code Playgroud)
也就是说,如果你真的关心,你可能用来实现所有Haskell的一个有效策略是使用thunk进行惰性求值.每个值都在一个框中表示,该框包含值或thunk子例程,当您最终需要使用它时,该子例程可用于计算值.
所以当你写作
let xs = 1 : []
Run Code Online (Sandbox Code Playgroud)
你会这样做:
x --> {thunk}
Run Code Online (Sandbox Code Playgroud)
如果你从不检查x的内容那么thunk保持不被评估.但是,如果您在thunk上进行了一些模式匹配,那么您需要评估thunk以查看您采用的分支:
case xs of
[] -> ...
(y:ys) -> ...
Run Code Online (Sandbox Code Playgroud)
现在,评估x的thunk并将结果值存储在框中以备不时之需.这是为了避免需要重新计算thunk.请注意,在下图中,我Cons用来代表:列表构造函数
x ---> {Cons {thunk} {thunk}}
^ ^
| |
y ys
Run Code Online (Sandbox Code Playgroud)
当然,仅仅存在模式数学是不够的,首先需要首先强制评估该模式匹配.最终,这归结为需要打印值或类似值的主要功能.
另一点需要指出的是,当我们第一次评估它时,我们没有立即评估Cons构造函数的内容.您可以通过运行不使用列表内容的程序来检查:
length [undefined, undefined]
Run Code Online (Sandbox Code Playgroud)
当然,当我们实际使用y某些东西时,它的相应thunk会被评估.
此外,您可以使用爆炸模式将构造函数字段标记为严格,以便在构造函数被评估时立即进行评估(我不记得您是否需要为此转换扩展)
data LazyBox = LazyBox Int
data StrictBox = StrictBox !Int
case (LazyBox undefined) of (LazyBox _) -> 17 -- Gives 17
case (StrictBox undefined) of (StrictBox _) -> 17 -- *** Exception: Prelude.undefined
Run Code Online (Sandbox Code Playgroud)
[1]:GHC所做的一个重要优化是在严格性分析器确定严格的部分中使用严格的评估.
[2]:最激进的例子之一就是森林砍伐.