尾递归和布尔运算符

时间:2013-04-06 21:32:51

标签: f# tail-recursion

我目前正在学习F#(通过试试f#网站)。 我有以下(imho)尾递归函数,用于存在统一一元谓词(int-> bool)。

let rec exists bound predicate = 
    if (bound<0) then false
    elif predicate(bound) then true
    else exists (bound-1) predicate

现在这个函数也可以写成

let rec exists bound predicate = (bound+1>0) && (predicate(bound) || exists (bound-1) predicate)

但是,第二个实现不是尾递归。问题是编译器是否会将其优化为尾递归?

情况如何更简单(好吧,有点傻)的例子,比如说

let rec hasNoRoot f = 
    if (f x = 0) then false
    else hasNoRoot (fun x -> f (x+1))

let rec hasNoRoot f = (f 0 <> 0) && (hasNoRoot (fun x-> f(x+1)))

在第二个例子中,为了将函数(它的描述实际上)识别为尾递归,编译器只需要“知道”为了评估一个连词,不一定必须评估两个连词。 / p>

感谢任何建议

1 个答案:

答案 0 :(得分:1)

我使用VS2012(F#3.0)编译了'exists'和'hasNoRoot'函数的第二个版本并进行了优化,然后使用.NET Reflector检查编译器生成的IL。编译器 优化'hasNoRoot'功能,但遗憾的是,它并没有优化'exists'功能。这似乎是一个合理的优化,所以它可能会被添加到下一版本的编译器中。

对于后代,这是编译器生成的内容:

.method public static bool exists(int32 bound, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, bool> predicate) cil managed
{
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = { new int32[int32(0x2)] { int32(0x1), int32(0x1) } }
    .maxstack 8
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: ldc.i4.1 
    L_0003: add 
    L_0004: ldc.i4.0 
    L_0005: ble.s L_001c
    L_0007: ldarg.1 
    L_0008: ldarg.0 
    L_0009: callvirt instance !1 [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, bool>::Invoke(!0)
    L_000e: brfalse.s L_0012
    L_0010: ldc.i4.1 
    L_0011: ret 
    L_0012: ldarg.0 
    L_0013: ldc.i4.1 
    L_0014: sub 
    L_0015: ldarg.1 
    L_0016: starg.s predicate
    L_0018: starg.s bound
    L_001a: br.s L_0001
    L_001c: ldc.i4.0 
    L_001d: ret 
}