Haskell 为什么评估会停止?

Haskell 为什么评估会停止?,haskell,Haskell,我有以下代码: foldr const 0 ([1] ++ undefined) 我得到的结果是1 我知道,foldr是正确关联的。写出上面的例子: const 1 (const undefined 0) 为什么括号中的表达式不作为第一个表达式计算 因为函数应用程序的优先级高于括号 为什么括号中的表达式不作为第一个表达式计算 Haskell使用惰性评估。这意味着当函数使用参数时,将对参数进行求值。这与在调用函数之前执行函数的所有参数的急切求值不同 因为函数应用程序的优先级高于括号 优先权与此

我有以下代码:

foldr const 0 ([1] ++ undefined)
我得到的结果是
1

我知道,
foldr
是正确关联的。写出上面的例子:

const 1 (const undefined 0)
为什么括号中的表达式不作为第一个表达式计算

因为函数应用程序的优先级高于括号

为什么括号中的表达式不作为第一个表达式计算

Haskell使用惰性评估。这意味着当函数使用参数时,将对参数进行求值。这与在调用函数之前执行函数的所有参数的急切求值不同

因为函数应用程序的优先级高于括号


优先权与此无关。优先级只是决定了操作数对什么(即“x???y!!!z”是运算符
对操作数
x
y!!!z
还是运算符
!!!
x???y
z
的应用)。它不影响评估顺序。

我相信您期望的是所谓的“应用评估顺序”。换句话说,在
f(gx)
中,您希望首先计算
gx
,然后对结果调用
f

在您的示例中,这意味着评估将从评估
0
[1]
未定义的
开始,我相信您预计会在这三个方面发生崩溃

Haskell有所谓的“按需调用”或“惰性评估”。在
f(gx)
中,首先计算
f
,将其作为参数提供一个程序(通常称为“thunk”)来计算
gx
。这意味着,如果
f
从不需要
gx
的值,则不会对其进行计算

下面是如何评估您的示例(我将
foldr
的定义放在下面以供参考):

下面是
foldr
(++)
的定义:


要正确计算
常量1(const undefined 0)
,我们需要了解
常量的定义、GHC使用的计算策略,以及(似乎)使用多个参数的函数中的curry行为。(不一定按那个顺序。)

const的定义
const的定义是

const c _ = c
咖喱 似乎包含多个参数的函数实际上是curry:

我们可以使用eta抽象(
fx=y
变成
f=\x->y
)显式curry
const
),将其转换为一个函数,该函数接受一个参数并给出另一个函数:

const c _ = c
= { eta abstraction }
const c = \_ -> c
将这两个概念结合起来意味着每当我们看到
const x y
,我们都可以用
(\\\ux->y
)替换它:

const x y
= { currying }
(const x) y
= { const c = \_ -> c }
(\_ -> x) y
最外层评估和短路 Haskell*中的计算从最外层的可约表达式(redex)开始,并由模式匹配触发。这意味着在
f(gx)
中,
f
gx
之前进行评估(它是最外层的)<然后,仅当
f
的评估需要时,才会评估code>gx
。然后,反过来,
x
仅在
g
的评估需要时才进行评估

最外层的第一次求值的属性之一是*短路(:如果外部表达式的求值不需要内部表达式的结果,则永远不会对内部表达式求值。特别是,这意味着
(\ \ ux->x)y=x
无论
y
是什么,因为
\\ux
不要求对
y
求值

计算常数1(常数未定义0)
把这些放在一起,我们可以计算
const 1(const undefined 0)

一旦你理解了这一点,就很容易跳过咖喱,只需写下:

const 1 (const undefined 0)
= { definition of const }
1
因为
const c_=c
c=1
,我们知道第二个参数永远不会被计算

(您还询问了优先级,但优先级与计算
常量1(常量未定义0)
无关)


*严格地说**,Haskell没有定义求值顺序。它指定求值必须是非严格的,并将此语义的实现留给Haskell实现。GHC使用惰性求值,这是与共享相结合的最外层第一求值(也就是说,
x
将在
中最多计算一次,让x*x中的x=1+1


**是的,这是一个双关语。

注意求值顺序和优先级是两个不同的概念,经常被错误地识别。即使在命令式语言中,
f()+g()*h()
也可以通过先调用
g()
,然后调用
f()
,然后调用
h()
(或任何其他顺序)来求值,然后执行乘法,最后是加法。你说的“上面”是指sepp2k的答案吗?不要假设一页上的答案有任何特定的顺序。
const c _ = c
= { eta abstraction }
const c = \_ -> c
const x y
= { currying }
(const x) y
= { const c = \_ -> c }
(\_ -> x) y
const 1 (const undefined 0)
= { const x y = (\_ -> x) y }
(\_ -> 1) (const undefined 0)
= { (\_ -> x) y = x }
1
const 1 (const undefined 0)
= { definition of const }
1