seq force如何运作?

时间:2011-06-22 15:00:31

标签: haskell semantics lazy-evaluation evaluation

背景

这个问题源于Brent Yorgey对OPLSS提出的挑战:编写一个函数f :: (Int -> Int) -> Bool,将f undefinedf (\x -> undefined)区分开来。我们所有的答案都使用了seq或类似于模糊的模式,而不是seq。例如:

f :: (Int -> Int) -> Bool
f g = g `seq` True

*Main> f undefined
*** Exception: Prelude.undefined
*Main> f (\x -> undefined)
True

GHC commentary on 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 吗?

{{1}}

2 个答案:

答案 0 :(得分:23)

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一旦达到一个就停止评估。

编译器可以使用。对于parunsafeCoerceRealWorld令牌,forkOn等其他原语也是如此。所有有用的东西。

答案 1 :(得分:9)

How to make a fast curry: push/enter vs eval/apply

中有更高级别的STG机器描述

图2包含适用于函数的规则CASEANY。在本文中,“是一个价值”命题意味着:

  • 这是一个饱和的构造函数应用程序
  • 这是一个功能
  • 它是一个部分功能应用程序(它仍然是一个功能,语义上)

特殊对待未包装的值,包括文字,可以在Unboxed values as first class citizens

中找到更多信息

所有这些都是实现细节,隐藏在编译器(GHC)中。 Haskell的case表达式并没有强制它的监督,只有模式匹配和seq这样做。