懒惰是让哈斯克尔保持纯洁的原因。如果严格的话,纯洁很快就会消失。
我看不到语言的评估策略和它的纯洁性之间的联系。考虑到推文作者的名声,我肯定忽略了一些东西。也许有人能给我们一些启示。
其他的答案给出了历史背景,这很可能是该评论所指的。我认为这种联系甚至更深。
热切的语言,即使是那些自称“纯粹”的语言,也不像在Haskell中那样具有强烈意义上的参照透明性:
let f = E in
\x -> f x
不等价于
\x -> E x
如果急切地求出前一个表达式,而e
的求值出现分歧。
急切的语言要求区分值和计算:变量仅用值替代,但表达式代表计算,这就是为什么上面的let
的“明显”缩减是无效的。一个表达式大于它所表示的值,这正是一种语言有效的含义。从这个非常技术的意义上讲,像Purescript(我在这个空间里能想到的第一个例子)这样的热切的语言并不纯粹。
当我们忽略了非终止性和求值顺序时,Purescript是纯粹的,这实际上是每个程序员都要做的,因此这值得赞扬。
相反,在懒惰语言中,值和计算之间的区别是模糊的。所有的东西都表示一个值,即使是非终止的表达式,也是“底”。您可以替换所有您想要的,而不必担心表达式的作用。在我看来,这才是纯洁的关键。
有人可能会说,实际上,我们也可以说eager语言中的发散表达式表示bottom,而let
表示严格的函数。老实说,这可能是一个很好的解释,但除了Haskellers和编程语言恐怖分子之外,没有人这么想。
这条推文有两个方面:第一,事实是,从技术角度来看,懒惰一般要求纯洁;其次,从实际的角度来看,严格仍然可以允许纯洁,但实际上它通常不允许(即,如果严格,纯洁就“走出窗外”)。
SimonPeyton-Jones在《哈斯克尔的历史:偷懒与阶级》一文中解释了这两个方面。关于技术方面,在第3.2节Haskell是纯粹的,他写道(我大胆强调):
懒惰的一个直接后果是评估顺序是需求驱动的。结果,作为函数调用的结果,变得或多或少不可能可靠地执行输入/输出或其他副作用。因此,Haskell是一种纯粹的语言。
如果你看不出为什么懒惰会让不纯效果变得不靠谱,我敢肯定那是因为你想多了。下面是一个简单的例子来说明这个问题。考虑一个假设的不纯函数,它从一个配置文件中读取一些信息,即一些“基本”配置和一些“扩展”配置,其格式取决于头中的配置文件版本信息:
getConfig :: Handle -> Config
getConfig h =
let header = readHeader h
basic = readBasicConfig h
extended = readExtendedConfig (headerVersion header) h
in Config basic extended
其中ReadHeader
,ReadBasicConfig
和ReadExtendedConfig
都是从文件中顺序读取字节(即使用典型的基于文件指针的顺序读取)并将它们解析为适当的数据结构的不纯函数。
在一个懒惰的语言中,这个函数可能不能按预期工作。如果header
,basic
和extended
变量值都是懒散求值的,那么如果调用方强制先执行basic
,然后执行extended
,则效果将按readbasic
,readheader
,readextendedconfig
的顺序调用;而如果调用方强制先执行extended
,后执行basic
,则效果将按ReadHeader
,ReadExtendedConfig
,ReadBasic
的顺序调用。在任何一种情况下,打算由一个函数解析的字节都将由另一个函数解析。
而且,这些求值顺序是严重的过度简化,它假定子函数的影响是“原子的”,并且readextendedconfig
可靠地强制使用版本参数来访问extended
。如果不是,根据basic
和extended
的哪些部分被强制执行,readbasic
,readextendedconfig
和readheader
中的(子)效果的顺序可能被重新排序和/或混合。
您可以通过不允许顺序文件访问来解决这个特定的限制(尽管这会带来一些很大的代价!),但是类似的不可预测的无序效应执行会导致其他I/O操作的问题(我们如何确保文件更新函数在截断文件以进行更新之前读取旧内容?),可变变量(锁变量到底什么时候递增?)等等。
关于实际方面(我再次大胆强调),SPJ写道:
一旦我们致力于一种懒惰的语言,一种纯洁的语言就不可避免了。反之亦然,但值得注意的是,实际上大多数纯编程语言也是懒惰的。为什么?因为在一种按值调用的语言中,不管是不是函数的,允许在一个“函数”内部不受限制的副作用的诱惑几乎是不可抗拒的。
。。。
因此,回想起来,也许懒惰最大的单一好处并不在于懒惰本身,而是在于懒惰使我们保持纯洁,从而激发了大量关于单子和封装状态的生产性工作。
在他的推文中,我相信赫顿指的不是懒惰导致纯洁性的技术后果,而是严格诱惑语言设计者放松纯洁性的实际后果“只是在这一个特殊情况下”,之后纯洁性很快就会消失。
你说得对,从现代的POV来看,这是没有意义的。事实是,默认情况下的懒惰会使关于副作用代码的推理成为一场噩梦,因此懒惰确实需要纯洁--但不是相反。
不过,Haskell在1.0-1.2版本中的做法确实需要懒惰,这是继其前身Miranda之后,在没有单子的情况下模仿IO的做法。除了副作用排序的明确概念外,可执行程序的类型是
main :: [Response] -> [Request]
对于一个简单的交互式程序,它的工作方式如下:main
一开始只会忽略它的输入列表。所以多亏了懒惰,这个列表中的值实际上不需要存在。同时,它将产生第一个request
值,例如一个终端提示,让用户键入一些内容。然后,键入的内容将作为响应
值返回,实际上现在才需要对该值进行计算,从而产生新的请求
,等等。
https://www.haskell.org/definition/haskell-report-1.0.ps.gz
在1.3版中,他们转换到了我们现在都知道和喜爱的monadic-IO接口,在那一点上,懒惰不再是真正必要的了。但在此之前,普遍的智慧是,与现实世界交互而不需要懒惰的唯一方法就是允许有副作用的函数,于是就有了这样的说法:如果没有懒惰,Haskell就只是走上了与它之前的Lisp和ML一样的道路。
Apache Cordova和PhoneGap有什么关系和区别?利弊分别是什么?
我有模型类别。它可能有父类别和子类别列表。我写这个问题是因为找不到实体和自己相关的情况。 我试图这样实现它: 我保存实体,如: 我希望看到这样的情况: 但是在子模型中,我有递归循环。如何防止它? 是的,我也使用了@JsonIgnore。但是我不确定这是不是一个好的做法。但是如果我有一个案例,当我需要一个类别时,我真的需要将它发送给父母的UI。@JsonIgnore可以产生这个吗?
问题内容: 在此示例中: 无法编译为: 而被编译器接受。 这个答案说明唯一的区别是,与不同,它允许您稍后引用类型,似乎并非如此。 是什么区别,并在这种情况下,为什么不第一编译? 问题答案: 通过使用以下签名定义方法: 并像这样调用它: 在jls§8.1.2中,我们发现(有趣的部分被我加粗了): 通用类声明定义了一组参数化类型(第4.5节), 每种可能通过类型arguments调用类型参数节的类型
我写了以下内容: 解决4clojure.com的问题#118:http://www.4clojure.com/problem/118 当我询问时,不出所料,我会得到一个clojure.lang.lazyseq,但我不知道这与简单地删除lazy-seq“包装”有什么区别。 当然,现在如果删除lazy-seq,我会得到一个stackoverflow,为什么要执行这个: 否则(也就是说:如果我让lazy
我有一个数据表的问题-懒加载。我认为问题是在IdiomasBean.java(TableBean.java),如果我把: 我得到了正确的数据表,但是<代码>按排序、筛选和不起作用。 我得到:java。lang.NullPointerException这里是堆栈跟踪: 下面是代码的其余部分: 指数xhtml diomasBean.java 懒散的数据模型。JAVA IdiomasBo.java 习语
我试着把我的头绕到相对较新的img属性“加载”上。 我知道,如果img具有load=“lazy”属性,那么它会告诉支持该属性的浏览器,在接近视口时可以加载该属性。 那么为什么不总是设置loading=“lazy”?那些立即出现在屏幕上的图像无论如何都会被渲染,因为它们已经在视口中了。因此,在这种情况下,基本上忽略了load=“lazy”。 在这个演示https://mathiasbynens.be
问题内容: 单向关联和双向关联有什么区别? 由于在数据库中生成的表都是相同的,所以我发现的唯一区别是双向关联的每一侧都有一个引用,而单向则没有。 这是单向关联 双向关联 区别在于该组是否持有用户的参考。 所以我想知道这是否是唯一的区别?哪个推荐? 问题答案: 主要区别在于,双向关系提供了双向导航访问,因此您无需显式查询即可访问另一侧。此外,它还允许您在两个方向上应用级联选项。 请注意,导航访问并不
我正在使用映射关系。我尝试了、和的几种组合,但到目前为止没有成功。 下面是MyEntity和MyEntityInfo类的代码(删除了额外的getter和setter): MyEntity(ID生成器是自定义序列生成器): 我已经设法使用和手动管理数据来做一些类似的事情,但这不是我想做的。但是,也欢迎使用或正确的设计模式来实现这一点的其他替代方案和信息。 PS:为SQL Server创建数据库表,如