Haskell definition说:
表达式是弱头正常形式(WHNF),如果它是:
- 一个构造函数(最终应用于参数),如True,Just(square 42)或(:) 1
- 内置函数应用于太少的参数(可能没有),如(+)2或sqrt。
- 或lambda abstraction \ x - >表达
为什么内置功能会受到特殊处理?根据lambda演算,部分应用函数和任何其他函数之间没有区别,因为最后我们只有一个参数函数。
答案 0 :(得分:22)
应用于参数的正常函数,如下所示:
(\x y -> x + 1 : y) 1
可以减少,给予:
\y -> 1 + 1 : y
在第一个表达式中,“最外层”的东西是一个应用程序,所以它不在WHNF中。在第二个中,最外层的东西是lambda抽象,所以它在WHNF中(即使我们可以在函数体内做更多的缩减)。
现在让我们考虑一下内置(原始)函数的应用:
(+) 1
因为这是一个内置函数,所以我们没有函数体可以用1
代替第一个参数。评估员“只知道”如何评估(+)
的完全“饱和”应用程序,如(+) 1 2
。但是,使用部分应用内置功能无法做到任何事情;我们所能做的就是产生一个描述“应用(+)到1并等待一个参数”的数据结构,但这正是我们试图减少的事情 。所以我们什么都不做。
内置函数是特殊的,因为它们不是由lambda演算表达式定义的,因此缩减过程不能“看到”它们的定义。因此,与普通函数应用程序不同,内置函数应用程序必须通过累积参数来“减少”,直到它们完全“饱和”(在这种情况下,通过运行内置的任何神奇实现来减少WHNF) 。不饱和的内置应用程序无法进一步减少,因此已经在WHNF中。
答案 1 :(得分:3)
考虑
前奏>设f n = [(+ x)| x< - [1 ..]] !! ñ
前奏>设g = f 20000000 :: Int - > INT
g
此时不在WHNF中!你可以通过评估g 3
来看到这一点,因为你需要WHNF然后才能应用一个参数,这需要一个明显的滞后。在搜索正确的内置函数时遍历列表时的情况。但之后,这个选择被修复,g
是WHNF(事实上NF:对于lambdas来说是相同的,也许你对你的问题意味着什么),因此任何后续调用都会立即给出结果。