seq 力如何发挥作用?

发布于 2024-11-16 10:42:31 字数 1160 浏览 5 评论 0原文

背景

这个问题源自 Brent Yorgey 在 OPLSS 上提出的挑战:编写一个函数 f :: (Int -> Int) -> Bool 区分 f undefinedf (\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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浮世清欢 2024-11-23 10:42:31

seq 无法在 Haskell 中实现。相反,它是一个原始的“钩子”,用于在 Haskell 运行的任何运行时对弱头范式进行求值。例如,在 GHC 上,它被编译为 GHC Core 中的一个 case,这会触发对最外层构造函数的求值。

由于它无法在纯 Haskell 中实现,因此(在 GHC 中)将其定义为 primop:

pseudoop   "seq"
       a -> b -> b
       { Evaluates its first argument to head normal form, and then returns its second
         argument as the result. }

由于函数没有范式,因此 seq 一旦达到 1,就会停止求值。

编译器神奇地可用。对于其他原语(例如 parunsafeCoerceRealWorld 令牌、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 a case 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:

pseudoop   "seq"
       a -> b -> b
       { Evaluates its first argument to head normal form, and then returns its second
         argument as the result. }

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 or unsafeCoerce, the RealWorld token, forkOn and so on. All the useful stuff.

惯饮孤独 2024-11-23 10:42:31

如何进行快速柯里化: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:

  • it is a saturated constructor application
  • it is a function
  • it is a partial function application (which is still a function, semantically)

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文