2

매우 높은 초기 currentReflection 값으로이 함수를 호출하면 스택 오버플로 예외가 발생합니다.이 함수는 tail-recursive (올바른?)가 아님을 나타냅니다. 필자가 알기로는 재귀 호출이 함수의 최종 계산 일 경우 현재 스택 프레임을 재사용하기 위해 꼬리 재귀 함수로 컴파일러 최적화되어야합니다. 이것이 여기에없는 이유는 누구나 아는가?이 F # 내부 함수가 꼬리 재귀가 아닌 이유는 무엇입니까?

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 

답변

4

traceColorAt에 대한 재귀 호출은 더 큰 표현식의 일부로 나타납니다. traceColorAt이 반환 된 후에 추가 계산이 필요하기 때문에 꼬리 호출 최적화를 방지합니다.

이 함수를 꼬리 재귀로 변환하려면 primaryColor에 대해 누적 기 매개 변수를 추가 할 수 있습니다. traceColorAt에 대한 가장 바깥 쪽 전화는 primaryColor (검정색)에 대한 "0"값을 전달할 것이며, 각각의 재귀 호출은 계산 된 합계를 합산합니다. 당신이 발신자의 추가 매개 변수를 숨기 대부분의 작업을 수행하는 도우미 함수를 소개하고 traceColorAt에서 해당 전화하려면

let rec traceColorAt intersection ray currentReflection primaryColor 
... 
let newPrimaryColor = primaryColor + ambient + diffuse + specular 
... 
match intersections with 
    | [] -> newPrimaryColor 
    | _ -> 
     ... 
     traceColorAt newIntersection newRay ((currentReflection - 1) * reflectivity) newPrimaryColor 

: 코드는 같을 것이다.

+0

완벽한 친구, 고마워. –

+0

함수 응용 프로그램은 함수 응용 프로그램보다 우선 순위가 높으므로 반사율에 의한 곱셈은 원본에서 재귀 호출 후에 수행됩니다. 따라서이 답변의 코드는 같은 것을 계산하지 않습니다. – RD1

4

꼬리 재귀는 다른 함수의 결과를 단순히 반환 할 경우 작동합니다. 이 경우 primaryColor + traceColorAt(...)이 있습니다. 즉, 단순히 함수의 값을 반환하는 것이 아니라 해당 함수에 값을 추가하는 것입니다.

현재 누적 된 색상을 매개 변수로 전달하여 문제를 해결할 수 있습니다.

+0

정확히 맞았습니다. 감사. –

관련 문제