懒惰的语言

时间:2011-11-16 14:35:43

标签: ocaml

我理解如果我有声明c = a AND b,如果a是假的,那么编译器就不会打扰评估b,它会知道结果,因为a已经是假的。

但是,如果我有一个递归函数和AND递归调用的函数会怎么样。

So myfunc input1 input2 = and[myfunc(input1),myfunc(input2)]

如果从上面的递归函数调用树中的任何一点返回的函数返回false,递归函数是否会调用terminate,而false值只会在原始调用点进行求值?

换句话说,它会使用上面的懒惰评估吗?

4 个答案:

答案 0 :(得分:8)

是。事实上,and一个实现是递归的(并没有添加任何严格性):

and :: [Bool] -> Bool
and []     =  True
and (x:xs) =  x && and xs

要证明这是有效的,您可以将False的无限列表传递给and,并看到它返回

Prelude> and (repeat False)
False

但是,请注意,这不适用于True的无限列表,因为它将永远查找False,但永远不会找到。{/ p>

答案 1 :(得分:6)

简而言之,答案是肯定的,Haskell在递归函数中会很懒惰。

&&的懒惰不是一个特例:它是其定义的结果:

(&&) :: Bool -> Bool -> Bool
True  && y = y
False && _ = False

在这里,Haskell的懒惰意味着它可以匹配&&的第一个参数,而不需要评估第二个参数来了解结果。

对于像and这样的递归函数,我们有定义:

and :: [Bool] -> Bool
and []     = True
and (b:bs) = b && and bs

这是一个递归定义,Haskell很懒,因为只有在需要时才会评估非空列表中bbs的值:在这种情况下,{{的定义1}}强制我们查看第一个元素&&,如果它是b,那么False的其余部分就不必进行评估。

这里的教训是,懒惰是Haskell通过其模式匹配提供的东西:当消耗足够的输入来匹配模式时,其余的可以保持不被评估,直到需要它为止。

答案 2 :(得分:2)

我是Haskell的新手,但是,它会评估左侧的整个递归调用树,并且只有当它们最终返回true时才会继续评估右侧的递归调用。 / p>

实际上,在您最终使用my_func的结果之前,它不会评估其中任何一个,但是如果您已经强制评估my_func,则上述情况就会出现。

将其视为传递承诺,为其所做的一切努力。因此调用my_func的结果不是结果,它是一个发现的承诺。它可能甚至没有考虑过这个承诺的意义,直到必须这样做。只有这样才能进入并弄清楚它需要调用什么。

我可能会离开,但这就是我理解它的方式。

答案 3 :(得分:2)

  

如果从上面的递归函数调用树中的任何一点返回的函数返回false,递归函数是否会调用terminate,而false值只会在原始调用点进行求值?

您可以编写依赖于该行为的递归调用。例如,如果将给定谓词函数exists应用于列表中的每个元素的结果为任何元素返回true,则OCaml中的以下p函数将返回true: / p>

let rec exists p = function
  | [] -> false
  | x::xs -> p x || exists p xs

由于短路评估,只要p第一次返回true,就会停止对列表进行迭代。

  

换句话说,它会使用上面的懒惰评估吗?

请注意,这是short-circuit evaluation而不是懒惰。