haskell - 具有头部功能的 Haskell 懒惰问题
问题描述
信息:
从文档和教程中它说:默认情况下“Haskell 是懒惰的”。
他们没有解释有关它的细节,我想知道。
现在我知道,如果我写:
filter odd [1, 2, 3]
在结果显示或在表达式中使用之前,它不会过滤结果。
我对此有几个问题:
函数是head
惰性的吗?
如果不是,为什么它不懒惰?
如果是惰性的,Haskell 编译器如何知道何时执行该函数?
我给你举个例子:
f a b = head a + head b
f [2, 3] [4, 5]
在这种情况下,从我的角度来看,head不会返回 2 + 4。
它将返回一些类型或函数,稍后将在需要时执行。(如果我在某个地方弄错了,请纠正我)。
所以我的建议是,当 Haskell 看到像“+”这样的操作时,它会计算结果。
但它变得更加复杂,因为对于整数我想如果我写3 + 5
它也可以是惰性表达式。
我怀疑当惰性表达式开始计算时是否存在函数列表,因为很难编写所有变体。
最后:
f head [1, 2]
假设在f
函数中我打印传递的变量的类型。
现在 Haskell 将如何知道是否应该传递 Int 1 或惰性表达式?
谢谢
解决方案
我认为这里有些混乱,因为“懒惰”一词有时会在两种不同的情况下使用。
- 惰性语义(相对于渴望语义)
- 惰性函数(实际上应该称为非严格函数)
关于惰性与渴望语义:考虑这个表达式
(\x -> 42) (error "urk!")
当上述评估时,结果是什么?
根据渴望语义,我们在调用函数之前评估参数。结果将是运行时错误。
根据惰性语义,我们立即调用该函数。这个过程可以从操作上和外延上理解如下。
在操作上,它被传递一个thunk,一个描述尚未评估的参数的对象,并且在x
需要参数时将被“强制”(评估)。我们可以假设x
指向未计算的表达式error "urk!"
,它将在x
需要时被计算。
在表示上,我们使用了一个数学技巧:我们用一个称为“底部”的特殊值来表示错误,并说它error "urk!"
具有这样的底部值。然后,我们简单地假设这个异常值可以被传递。在上面的函数调用中,x
将绑定到“底部”,就好像它是一个正常值一样。这可以说更简单,因为我们不需要关注表达式是如何计算的,而只需要关注底部是如何传播的。
更准确地说,我们让“底部”表示运行时错误和非终止(无限递归),这两者都让程序能够返回实际结果。
例如,我们if bottom then .. else ..
总是会产生底部。类似地bottom + 4
,它是底部。再次,case bottom of SomeConstructor -> ...; ...
是底部(好吧,除了newtypes
,但让我们忽略这一点)。取而代之f bottom
的可能是也可能不是底部,具体取决于做什么f
:如果它需要参数,则结果将是底部。
关于惰性(非严格)函数。一个函数f
有时被称为“惰性的”(或者,更准确地说,是非严格的)当且仅当且仅当f bottom
是底部。
例如:
f x = x+1 -- strict / non lazy
f x = 5 -- non strict / lazy
head xs = case xs of -- strict / non lazy
[] -> error "head: empty list"
(x:xs) -> x
g x = (x,True) -- non strict / lazy
所以,既然head bottom
是case bottom of ...
底,head
就不懒了。在操作上,由于head
在产生结果之前需要它的参数,所以它是严格/非懒惰的。
About g
:惰性语义的一个主要特征是data
像对构造函数这样的构造(,)
函数本质上是惰性的。这(bottom, 4)
与底部不同:这使得snd (bottom, 4) = 4
即使第一对组件是“错误”值也可以具有。
所以,g bottom = (bottom, True)
不是底部,我们可以在不触发错误的情况下申请snd
提取。True
推荐阅读
- javascript - Sharepoint Online,格式列在 Web 部件中不起作用
- mysql - MySQL 是否有“打印”功能来显示自定义文本输出?
- c# - ASP.NET Core:我想从我对控制器方法的视图中访问复选框(值)列表
- php - XML在PHP中按属性选择数据
- docker - jenkins 作为 docker 容器拒绝连接到 ubuntu 中的 docker 守护进程
- javascript - History.popState() 不适用于 YouTube 导航
- python - Pyspark dataframe isin 函数数据类型转换
- c# - 左外连接 - 如何检测空值?
- javascript - 很难在 Vue js 中更改背景颜色
- sql - 读取在 oracle DB 中保存为 blob 的 SQLite 格式 3 DB 文件