这个问题源于Brent Yorgey对OPLSS提出的挑战:编写一个函数f :: (Int -> Int) -> Bool
,将f undefined
与f (\x -> undefined)
区分开来。我们所有的答案都使用了seq
或类似于模糊的模式,而不是seq
。例如:
f :: (Int -> Int) -> Bool
f g = g `seq` True
*Main> f undefined
*** Exception: Prelude.undefined
*Main> f (\x -> undefined)
True
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}}
答案 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
一旦达到一个就停止评估。
编译器可以使用。对于par
或unsafeCoerce
,RealWorld
令牌,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这样做。