Recursion 为什么不是';这个F#内部函数是递归的吗?
如果使用非常高的初始currentReflection值调用此函数,则会出现堆栈溢出异常,这表明该函数不是尾部递归的(正确吗?)。我的理解是,只要递归调用是函数的最终计算,那么它就应该作为尾部递归函数进行编译器优化,以重用当前堆栈帧。有人知道为什么这里不是这样吗Recursion 为什么不是';这个F#内部函数是递归的吗?,recursion,f#,functional-programming,tail-recursion,tail-call-optimization,Recursion,F#,Functional Programming,Tail Recursion,Tail Call Optimization,如果使用非常高的初始currentReflection值调用此函数,则会出现堆栈溢出异常,这表明该函数不是尾部递归的(正确吗?)。我的理解是,只要递归调用是函数的最终计算,那么它就应该作为尾部递归函数进行编译器优化,以重用当前堆栈帧。有人知道为什么这里不是这样吗 let rec traceColorAt intersection ray currentReflection = // some useful values to compute at the start
let rec traceColorAt intersection ray currentReflection =
// some useful values to compute at the start
let matrix = intersection.sphere.transformation |> transpose |> invert
let transNormal = matrix.Transform(intersection.normal) |> norm
let hitPoint = intersection.point
let ambient = ambientColorAt intersection
let specular = specularColorAt intersection hitPoint transNormal
let diffuse = diffuseColorAt intersection hitPoint transNormal
let primaryColor = ambient + diffuse + specular
if currentReflection = 0 then
primaryColor
else
let reflectDir = (ray.direction - 2.0 * norm ((Vector3D.DotProduct(ray.direction, intersection.normal)) * intersection.normal))
let newRay = { origin=intersection.point; direction=reflectDir }
let intersections = castRay newRay scene
match intersections with
| [] -> primaryColor
| _ ->
let newIntersection = List.minBy(fun x -> x.t) intersections
let reflectivity = intersection.sphere.material.reflectivity
primaryColor + traceColorAt newIntersection newRay (currentReflection - 1) * reflectivity
如果函数只返回另一个函数的结果,尾部递归就可以工作。在本例中,您有
primaryColor+tracecolor(…)
,这意味着它不仅返回函数的值,还向函数添加了一些内容
您可以通过将当前累积颜色作为参数传递来解决此问题。对
TraceColort
的递归调用显示为较大表达式的一部分。这会阻止尾部调用优化,因为在TraceColort
返回后需要进一步计算
要将此函数转换为尾部递归函数,可以为primaryColor
添加额外的累加器参数。对TraceColort
的最外层调用将传递primaryColor
(黑色?)的“零”值,并且每个递归调用将在其计算的调整中求和,例如,代码看起来类似于:
let rec traceColorAt intersection ray currentReflection primaryColor
...
let newPrimaryColor = primaryColor + ambient + diffuse + specular
...
match intersections with
| [] -> newPrimaryColor
| _ ->
...
traceColorAt newIntersection newRay ((currentReflection - 1) * reflectivity) newPrimaryColor
如果希望对调用者隐藏额外的参数,请引入一个执行大部分工作的helper函数,并从
traceColorAt
调用该函数。函数应用程序的优先级高于函数应用程序,因此,反射率乘法是在原函数的递归调用之后进行的。所以,这个答案中的代码计算的结果不一样。