seq 力如何发挥作用?
背景
这个问题源自 Brent Yorgey 在 OPLSS 上提出的挑战:编写一个函数 f :: (Int -> Int) -> Bool
区分 f undefined
和 f (\x -> undefined)
。我们所有的答案都使用了 seq
或类似 bang 模式的东西,将糖分转化为 seq
。例如:
f :: (Int -> Int) -> Bool
f g = g `seq` True
*Main> f undefined
*** Exception: Prelude.undefined
*Main> f (\x -> undefined)
True
GHC 对 seq
的评论说,
e1 `seq` e2
使用脱糖,
case e1 of { _ -> e2 }
所以我尝试手动脱糖。它不起作用:
f' g = case g of { _ -> True }
*Main> f' undefined
True
*Main> f' (\x -> undefined)
True
问题
此行为是否取决于描述的更复杂的seq
在评论末尾,如果是这样,它是如何运作的?如果没有这些原语,可以编写这样的 f
吗?
x `seq` e2 ==> case seq# x RW of (# x, _ #) -> e2 -- Note shadowing!
e1 `seq` e2 ==> case seq# x RW of (# _, _ #) -> e2
Background
This question arises from a challenge Brent Yorgey posed at OPLSS: write a function f :: (Int -> Int) -> Bool
that distinguishes f undefined
from f (\x -> undefined)
. All of our answers either used seq
or something like bang patterns that desugar into seq
. For example:
f :: (Int -> Int) -> Bool
f g = g `seq` True
*Main> f undefined
*** Exception: Prelude.undefined
*Main> f (\x -> undefined)
True
The GHC commentary on seq
says that
e1 `seq` e2
used to desugar into
case e1 of { _ -> e2 }
so I tried desugaring manually. It didn't work:
f' g = case g of { _ -> True }
*Main> f' undefined
True
*Main> f' (\x -> undefined)
True
Question
Does this behavior depend on the more complex seq
described at the end of the commentary, and if so, how does it work? Could such an f
be written without these primitives?
x `seq` e2 ==> case seq# x RW of (# x, _ #) -> e2 -- Note shadowing!
e1 `seq` e2 ==> case seq# x RW of (# _, _ #) -> e2
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
seq
无法在 Haskell 中实现。相反,它是一个原始的“钩子”,用于在 Haskell 运行的任何运行时对弱头范式进行求值。例如,在 GHC 上,它被编译为 GHC Core 中的一个case
,这会触发对最外层构造函数的求值。由于它无法在纯 Haskell 中实现,因此(在 GHC 中)将其定义为 primop:
由于函数没有范式,因此
seq
一旦达到 1,就会停止求值。编译器神奇地可用。对于其他原语(例如
par
或unsafeCoerce
、RealWorld
令牌、forkOn
等)也是如此。所有有用的东西。seq
cannot be implemented in Haskell. Instead, it is a primitive "hook" into evaluation to weak-head normal form in whatever runtime your Haskell is running on. E.g. on GHC it is compiled to acase
in GHC Core, which triggers evaluation to the outermost constructor.Since it can't be implemented in pure Haskell, it is defined (in GHC) as a primop:
Since functions don't have a normal form,
seq
halts evaluation once it reaches one.Magically available to the compiler. The same goes for other primitives like
par
orunsafeCoerce
, theRealWorld
token,forkOn
and so on. All the useful stuff.如何进行快速柯里化:push/enter 与 eval/apply
图 2 包含适用于函数的规则 CASEANY。在本文中,“是一个值”命题意味着:
未装箱的值,包括文字被特殊处理,更多信息可以发现于作为一等公民的未装箱值< /a>
全部这些是实现细节,隐藏在编译器(GHC)内。 Haskell 的 case 表达式不会强制它的审查者,只有模式匹配和 seq 会这样做。
There is a more higher-level description of STG-machine in How to make a fast curry: push/enter vs eval/apply
Figure 2 contains rule CASEANY that works for functions. In this paper "is a value" proposition means either:
Unboxed values, including literals are treated specially, more information can be found in Unboxed values as first class citizens
All these are implementation details and are hidden inside compiler (GHC). Haskell's case expression doesn't force it's scrutineer, only pattern-matching and seq do.