我理解如果我有语句c = a AND b,如果a是假的那么编译器就不会打扰评估b,它会知道结果因为a已经是假的.
但是,如果我有一个递归调用的函数并且将递归调用与AND进行AND运算会怎么样呢.
So myfunc input1 input2 = and[myfunc(input1),myfunc(input2)]
Run Code Online (Sandbox Code Playgroud)
如果一个函数从上面的递归函数调用树中的任何一点返回false,那么递归函数会调用终止,而值false是否只会在原始调用点进行求值?
换句话说,它会使用上面的懒惰评估吗?
是.实际上,一个实现and
是递归的(并没有添加任何严格性):
and :: [Bool] -> Bool
and [] = True
and (x:xs) = x && and xs
Run Code Online (Sandbox Code Playgroud)
为了表明这是有效的,你可以传递一个无限的False
s 列表and
,并看到它返回
Prelude> and (repeat False)
False
Run Code Online (Sandbox Code Playgroud)
但请注意,这不适用于无限的True
s 列表,因为它将永远寻找a False
,但永远不会找到它.
简而言之,答案是肯定的,Haskell在递归函数中会很懒惰.
懒惰&&
不是一个特例:它是其定义的结果:
(&&) :: Bool -> Bool -> Bool
True && y = y
False && _ = False
Run Code Online (Sandbox Code Playgroud)
在这里,Haskell的懒惰意味着它可以匹配第一个参数&&
,而第二个参数不需要被评估以了解结果.
对于递归函数,and
我们有定义:
and :: [Bool] -> Bool
and [] = True
and (b:bs) = b && and bs
Run Code Online (Sandbox Code Playgroud)
这是一个递归定义,Haskell是在这些值懒惰b
和bs
在非空列表,如果需要将只进行评估:在这种情况下,定义&&
迫使我们来看看第一个元素b
,如果是False
,则其余的bs
不必评估.
这里的教训是,懒惰是Haskell凭借其模式匹配提供的东西:当消耗足够的输入来匹配模式时,其余的可以保持不被评估直到需要它为止.