gpt4 book ai didi

recursion - 为什么这个 F# 内部函数不是尾递归的?

转载 作者:行者123 更新时间:2023-12-03 07:56:57 25 4
gpt4 key购买 nike

如果我用一个非常高的初始 currentReflection 值调用这个函数,我会得到一个堆栈溢出异常,这表明该函数不是尾递归的(正确吗?)。我的理解是,只要递归调用是函数的最终计算,那么它就应该作为尾递归函数进行编译器优化,以重用当前堆栈帧。有人知道为什么这里不是这种情况吗?

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

最佳答案

traceColorAt 的递归调用显示为更大表达式的一部分。这会阻止尾调用优化,因为在 traceColorAt 返回后需要进一步计算。

要将此函数转换为尾递归函数,您可以为 primaryColor 添加一个额外的累加器参数。对 traceColorAt 的最外层调用将传递 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

如果您希望对调用者隐藏额外参数,请引入一个辅助函数来执行大部分工作并从 traceColorAt 调用它。

关于recursion - 为什么这个 F# 内部函数不是尾递归的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5281248/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com