Sib*_*ibi 11 haskell lazy-evaluation purely-functional
我记得看到一个演示文稿,其中SPJ说懒惰评估迫使他们保持Haskell纯粹(或沿着那条线).我经常看到许多Haskellers说同样的话.
所以,我想了解懒惰的评估策略是如何迫使他们保持Haskell纯粹而不是严格的评估策略?
懒惰的评价并没有导致纯度; Haskell一开始就是纯粹的.相反,懒惰的评估迫使语言的设计者保持语言纯洁.
以下是Haskell的历史:与班级一起懒惰的文章的相关段落:
一旦我们致力于一种懒惰的语言,一个纯粹的语言是不可避免的.反之亦然,但值得注意的是,在实践中,大多数纯编程语言也是懒惰的.为什么?因为在一种按值调用的语言中,无论是否有功能,在"功能"内允许不受限制的副作用的诱惑几乎是不可抗拒的.
纯度是一个很大的赌注,具有普遍的后果.毫无疑问,不受限制的副作用非常方便.缺乏副作用,Haskell的输入/输出最初是痛苦的笨拙,这是一个相当尴尬的来源.作为发明之母的必要性,这种尴尬最终导致了monadic I/O的发明,我们现在将其视为Haskell对世界的主要贡献之一,正如我们在第7节中更详细地讨论的那样.
纯语言(具有monadic效应)是否最终是编写程序的最佳方式仍然是一个悬而未决的问题,但它肯定是对编程挑战的一种激进而优雅的攻击,正是这种力量与美的结合促使了设计师.因此,回想起来,也许懒惰的最大单一好处不是懒惰本身,而是懒惰使我们保持纯洁,从而激发了对单子和封装状态的大量生产性工作.
(我的重点)
我还邀请你听听软件工程电台播客#108的 18'30'',以获得该人自己的解释.这是SPJ在Peter Seibel的" 工作中的编码员"访谈中的一段较长但相关的段落:
我现在认为懒惰的重要之处在于它让我们保持纯洁.[...]
[...]如果你有一个惰性求值器,那么很难准确预测何时要对一个表达式进行求值.所以这意味着如果你想在屏幕上打印一些内容,每个按值调用的语言,评估的顺序是完全明确的,那就是通过一个不纯的"功能" - 我在它周围加上引号,因为它现在根本不是一个函数 - 类型为字符串到单位.你调用这个函数,作为一个副作用,它会在屏幕上放置一些东西.这就是Lisp中发生的事情; 它也发生在ML.它基本上发生在每个按值调用的语言中.
现在用纯语言,如果你有一个从字符串到单元的函数,你就永远不需要调用它,因为你知道它只是给出了答案单元.这就是功能所能做到的,就是给你答案.你知道答案是什么.但是当然如果它有副作用,那么你做它的调用非常重要.在一种懒惰的语言中,如果你说"f应用于打印"hello","就会出现问题,那么f是否评估其第一个参数对于函数的调用者来说是不明显的.这与函数的内部有关.如果你传递两个参数,即打印"hello"和打印"goodbye",那么你可以按任意顺序打印其中一个或两个,或者两者都不打印.所以,不知何故,对于懒惰的评估,通过副作用进行输入/输出是不可行的.你无法用这种方式编写合理,可靠,可预测的程序.所以,我们不得不忍受这一点.真的有点尴尬,因为你无法真正做任何输入/输出.所以很长一段时间我们基本上都有程序可以把一个字符串带到一个字符串.这就是整个计划的作用.输入字符串是输入,结果字符串是输出,这是所有程序真正可以做的.
通过使输出字符串编码由某些外部解释器解释的某些输出命令,您可能会有点聪明.所以输出字符串可能会说:"在屏幕上打印; 把它放在磁盘上."翻译实际上可以做到这一点.因此,您可以想象功能程序都很好而且纯粹,并且有一种这种邪恶的解释器可以解释一串命令.但是,当然,如果您阅读文件,如何将输入重新输入程序?嗯,这不是问题,因为您可以输出由邪恶解释器解释并使用延迟评估的一串命令,它可以将结果转储回程序的输入.因此,该程序现在对一组请求进行响应.请求流发送到向世界做事的邪恶翻译.每个请求都会生成一个响应,然后反馈给输入.而且由于评估是懒惰的,程序及时发出响应,使其绕过循环并作为输入使用.但它有点脆弱,因为如果你过于急切地消耗你的反应,那么你会遇到某种僵局.因为你要问的是你还没有从后端吐出问题的答案.
这就是懒惰让我们陷入了一个角落,在这个角落里我们不得不想办法解决这个I/O问题.我认为这非常重要.关于懒惰的最重要的一点是它把我们赶到了那里.
(我的重点)
我认为Jubobs的答案已经很好地总结了(有很好的参考).但是,用我自己的话说,我认为SPJ和朋友所指的是:
必须经历这个"monad"业务有时会非常不方便.关于Stack Overflow的大量问题询问"我该如何删除这个IO
东西?" 是证明了一个事实,有时,你真的真的只想打印出这个值就在这里-通常是搞清楚什么实际****是怎么回事的目的!
用一种急切的语言,开始添加神奇的不纯函数会让你直接输入东西,就像在其他语言中一样.毫无疑问,你首先要从小东西开始,但慢慢地你滑下这个滑坡,在你知道它之前,效果到处都是.
在像哈斯克尔这样的懒惰语言中,这种诱惑仍然存在.很多时候,能够在这里或那里快速潜入这一点效果真的很有帮助.除了因为懒惰,添加效果几乎完全没用.您无法控制何时发生任何事情.即使只是Debug.trace
倾向于产生完全不可理解的结果.
简而言之,如果你正在设计一种懒惰的语言,你真的被迫想出一个关于你如何处理效果的连贯故事.你不能只是去"我,我们会假装这个功能只是魔术"; 如果没有更准确地控制效果的能力,你将立即陷入可怕的混乱!
TL; DR用急切的语言,你可以逃避作弊.在懒惰的语言中,你真的必须正确地做事,或者它只是简单的不起作用.
而这就是为什么我们聘请了亚历克斯-等待,错误的窗口...