Open DeveloperYard opened 1 year ago
static int fact(int n)
{
if(n < 2) return 1;
return n * fact(n-1);
}
/*
(fact 3)
(* 3 (fact 2))
(* 3 (* 2 (fact 1)))
(* 3 (* 2 (* 1 (fact 0)))) // 여기까지 스택쌓임
(* 3 (* 2 (* 1 1))) // 스택빠지기 시작
(* 3 (* 2 1))
(* 3 2)
6
*/
static int fact(int n){
return fact_tail(n, 1);
}
static int fact_tail(int n, int total){
if(n < 1) return total;
return fact_tail(n - 1, n * total);
}
/*
(fact 3)
(fact_tail 3 1)
(fact_tail 2 3)
(fact_tail 1 6)
(fact_tail 0 6)
6
*/
스칼라, 코틀린 등의 경우 다음과 같이 컴파일러가 자체적으로 꼬리 재귀 최적화를 한다.
// 이코드를
static int fact_tail(int n, int total){
if(n < 1) return total;
return fact_tail(n - 1, n * total);
}
// while 반복문으로 자동 최적화하여 바이트코드로 변환함
static int fact_tail(int n, int total){
while(n != 1) {
int var = total * n;
--n;
total = var;
}
return total;
}
그러나 자바에서는 스택 프레임의 수에 의존하는 몇몇 jdk클래스가 존재하는데 프레임을 변경했을 때 오류가 발생할 수 있기 때문에 자동 꼬리 호출 최적화를 지원하지 않는다. 자바8의 람다식과 함수형 인터페이스를 사용하면 내부반복으로 직접 꼬리호출을 최적화할 수 있다.
문제
재귀와 꼬리 호출의 차이점과 꼬리 호출은 어떻게 최적화가 되는 걸까요?
contents - 세부 내용
예전에 찾아본 적이 있었는데 책에는 자세한 내용이 없는 것 같아 이슈로 삼았습니다.
참고
582p