【问题标题】:Can pseq be defined in terms of seq?pseq可以用seq来定义吗?
【发布时间】:2017-02-11 21:18:23
【问题描述】:

据我所知,seq a b 在返回 b 之前评估(强制)ab。它不保证首先评估a

pseq a b 首先评估a,然后评估/返回b

现在考虑以下几点:

xseq a b = (seq a id) b

函数应用需要先对左操作数求值(得到一个 lambda 形式),在进入函数之前不能盲目求右操作数,因为这会违反 Haskell 的非严格语义。

因此(seq a id) b 必须首先评估seq a id,这会强制aid(以某种未指定的顺序(但评估id 什么都不做)),然后返回id b(即b );因此xseq a bb 之前评估a

xseqpseq 的有效实现吗?如果不是,上述论点有什么问题(是否可以根据seq 定义pseq)?

【问题讨论】:

  • 如果编译器决定将id 内联成seq a (\x->x),那么它还可以看到\x -> x 在WHNF 中,所以seq a (\x->x) 可以“优化”为apseq 实际上是根据 seqlazy 实现的,这是一个“非常神奇”的标识函数,编译器知道在严格性分析期间永远不会内联。
  • 你正在寻找的魔法真的在lazy
  • @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,只是在操作上没有)
  • 您似乎认为f x 必须首先将f 评估为WHNF,但事实可能并非如此。如果严格性分析器证明f 严格,我认为运行时可以首先将x 评估为WHNF,而无需更改语义。我不确定这是否真的发生在 GHC 优化器中。
  • 我看到到目前为止有五个人对这个问题投了反对票。我很想知道为什么。

标签: haskell lazy-evaluation strictness


【解决方案1】:

答案似乎是“不,至少没有额外的魔法”。

问题

xseq a b = (seq a id) b

是编译器可以看到seq a id的结果是id,处处严格。如果函数是严格的,则允许函数应用程序首先评估参数,因为这样做不会改变表达式的语义。因此,优化编译器可以首先开始评估 b,因为它知道它最终会需要它。

【讨论】:

  • 这是一个美丽的问题和答案。
【解决方案2】:

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 实现,这可能工作:

import Prelude(seq)

infixr 0 `pseq`
pseq :: a -> b -> b
pseq x y = x `seq` (case x of _ -> y)

可能结合 - 至少 - 相当于:

 -- for GHC 8.6.5
{-# NOINLINE pseq #-}

我会让 melpomene 决定这是否也符合镜面烟雾的条件...

【讨论】:

  • 任何-O0 不执行严格分析的实现都应该允许您在其自己的模块中定义lazy 的低效版本。 lazy :: a -> a; lazy x = x {-# NOINLINE lazy #-}。只要模块没有显示lazy 在其论点中实际上是严格的,并且不会为其产生展开,那么您应该是好的。 GHC 特殊功能将其内联在 Core Prep 中,就在 core-to-core 编译管道的末尾。
猜你喜欢
  • 2016-03-27
  • 2012-01-04
  • 1970-01-01
  • 1970-01-01
  • 2011-06-02
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多