为什么评估会停止?

时间:2017-06-14 15:08:46

标签: haskell

我有以下代码:

foldr const 0 ([1] ++ undefined)

我得到了结果1

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

const 1 (const undefined 0)

为什么括号中的表达式不会被评估为第一个?

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

3 个答案:

答案 0 :(得分:6)

  

为什么括号中的表达式不会被评估为第一个?

Haskell使用惰性评估。这意味着如果函数使用它,则计算参数。这与急切评估的不同之处在于,在调用函数之前执行函数的所有参数。

  

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

优先权与它无关。优先级只是确定操作数是什么(即“x ??? y !!! z”是操作符???对操作数xy !!! z或操作符的应用程序!!!x ??? yz)。它不会影响评估顺序。

答案 1 :(得分:3)

为了正确评估const 1 (const undefined 0),我们需要知道const的定义,GHC使用的评估策略,以及(似乎)采用多个参数的函数中的currying行为。 (不一定按顺序。)

const

的定义

const的定义是

const c _ = c

柯里

似乎带有多个参数的函数实际上是 curried

f x y = (f x) y

我们可以使用 eta abstraction const变为f x = y)明确地讨论f = \x -> y,将其转换为一个接受参数并提供另一个函数的函数:

const c _ = c
= { eta abstraction }
const c = \_ -> c

结合这两个概念意味着每当我们看到const x y时,我们都可以将其替换为(\_ -> x) y

const x y
= { currying }
(const x) y
= { const c = \_ -> c }
(\_ -> x) y

最外面的评估和短路

Haskell *中的评估从最外层的可简化表达式(redex)开始,并由模式匹配触发。这意味着在f (g x)f会在g x之前评估(它是最外层)。然后,只有在g x的评估要求时才会评估f。然后,只有在x的评估要求时才会评估g

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

评估const 1 (const undefined 0)

将这些放在一起,我们可以评估const 1 (const undefined 0)

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

因为const c _ = cc = 1,我们知道第二个参数永远不会被评估。

(您还询问了优先级,但优先级与const 1 (const undefined 0)的评估无关。)

*严格来说**,Haskell没有定义评估顺序。它指定评估必须是非严格,并将此语义的实现留给Haskell实现。 GHC使用延迟评估,这是最外层评估与共享相结合(表示x最多只评估一次let x = 1 + 1 in x * x

**是的,这是双关语。

答案 2 :(得分:2)

我相信您期待所谓的“应用评估顺序”#34;换句话说,在f (g x)中,您希望首先评估g x,然后在结果上调用f

在您的示例中,这意味着评估将从评估0[1]undefined开始,这是我认为您希望崩溃的地方。

Haskell有所谓的"需要呼叫"或者"懒惰的评价"。在f (g x)中,首先评估f,将其作为参数提供给程序(通常称为" thunk")以评估g x。这意味着,如果g x永远不需要f的值,则永远不会对其进行评估。

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

  foldr const 0 ([1] ++ undefined)          -- one step of evaluation of ++
= foldr const 0 (1 : ([] ++ undefined))     -- second equation of foldr
= const 1 (foldr const 0 ([] ++ undefined)) -- evaluate const
= 1

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

foldr _ z []     =  z
foldr f z (x:xs) =  f x (foldr f z xs)

(++) [] ys = ys
(++) (x:xs) ys = x : (xs ++ ys)