Haskell pseq可以用seq定义吗?
据我所知,Haskell pseq可以用seq定义吗?,haskell,lazy-evaluation,strictness,Haskell,Lazy Evaluation,Strictness,据我所知,seq a b在返回b之前计算(强制)a和b。它不保证首先计算a pseq a b首先计算a,然后计算/返回b 现在考虑以下内容: xseq a b = (seq a id) b 函数应用程序需要首先计算左操作数(以获得lambda形式),并且在进入函数之前不能盲目计算右操作数,因为这将违反Haskell的非严格语义 因此(seq a id)b必须首先计算seq a id,它强制a和id(按一些未指定的顺序(但计算id什么都不做)),然后返回id b(即b);因此xseq a b在b
seq a b
在返回b
之前计算(强制)a
和b
。它不保证首先计算a
pseq a b
首先计算a
,然后计算/返回b
现在考虑以下内容:
xseq a b = (seq a id) b
函数应用程序需要首先计算左操作数(以获得lambda形式),并且在进入函数之前不能盲目计算右操作数,因为这将违反Haskell的非严格语义
因此(seq a id)b
必须首先计算seq a id
,它强制a
和id
(按一些未指定的顺序(但计算id
什么都不做)),然后返回id b
(即b
);因此xseq a b
在b
之前对a
进行求值
xseq
是pseq
的有效实现吗?如果没有,上面的论点有什么问题(是否可以用seq
来定义pseq
)答案似乎是“没有,至少没有额外的魔力”
问题在于
xseq a b = (seq a id) b
编译器可以看到seq a id
的结果是id
,这在任何地方都是严格的。如果函数是严格的,则允许函数应用程序首先计算参数,因为这样做不会更改表达式的语义。因此,优化编译器可以首先开始计算b
,因为它知道它最终将需要它
pseq
是否可以用seq
来定义
在GHC中-是
正如Alec所指出的,您还需要镜像烟雾lazy
:
-- for GHC 8.6.5
import Prelude(seq)
import GHC.Base(lazy)
infixr 0 `pseq`
pseq :: a -> b -> b
pseq x y = x `seq` lazy y
与GHC来源中对应的定义相匹配;进口商品是
非常不同
对于其他Haskell实现,这可能会起作用:
可能与(至少)相当于:
-- for GHC 8.6.5
{-# NOINLINE pseq #-}
我将让melpomene决定这是否也符合镜像烟雾…如果编译器决定内联
id
以形成seqa(\x->x)
,那么它还可以看到\x->x
在WHNF中,因此seqa(\x->x)
可以“优化”为a
。实际上是按照seq
和来实现的,这是一个“非常神奇”的标识函数,编译器知道在严格性分析过程中永远不会内联。你要寻找的魔法真的存在。@melpomene抱歉,我的意思是seq a(\x->x)b
可以变成seq a((\x->x)b)
-一般来说,如果y
在WHNF中,则seq a y o
可能变成seq a(y o)
。我不知道编译器是否会执行这样的优化,但它肯定会。我相信,就“原始操作语义”(即假装编译器根本不会更改代码)而言,您的函数是正确的——它只是在出现优化时发生故障。(事实上,lazy
从字面上等同于id
——因此你的xseq
从字面上等同于pseq
,并且两者都等同于seq
,只是在操作上不一样)你似乎认为fx
必须首先计算f
,但情况可能不是这样。如果strictness analyzer证明f
strict,我认为运行时可以首先将x
计算为WHNF,而不改变语义。我不确定这是否真的发生在GHC优化器中。到目前为止,我看到有五个人对这个问题投了反对票。我很想知道为什么。这是一个漂亮的问题和答案。任何-O0
没有执行严格性分析的实现都应该允许您在其自己的模块中定义一个低效版本的lazy
<代码>懒惰::a->a;lazy x=x{-#NOINLINE lazy}。只要模块没有显示lazy
在其参数中实际上是严格的,并且没有为其生成展开,您就应该是好的。GHC special将其内联到Core Prep中,就在Core-to-Core编译管道的末尾。
-- for GHC 8.6.5
{-# NOINLINE pseq #-}