我有以下代码:
foldr const 0 ([1] ++ undefined)
我得到了结果1
。
我知道,foldr
是正确关联的。写出上面的例子:
const 1 (const undefined 0)
为什么括号中的表达式不会被评估为第一个?
因为函数应用程序的优先级高于括号吗?
答案 0 :(得分:6)
为什么括号中的表达式不会被评估为第一个?
Haskell使用惰性评估。这意味着如果函数使用它,则计算参数。这与急切评估的不同之处在于,在调用函数之前执行函数的所有参数。
因为函数应用程序的优先级高于括号吗?
优先权与它无关。优先级只是确定操作数是什么(即“x ??? y !!! z”是操作符???
对操作数x
和y !!! z
或操作符的应用程序!!!
至x ??? y
和z
)。它不会影响评估顺序。
答案 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 _ = c
,c = 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)