올바른 꼬리 호출과 재귀

꼬리 적용은 명시적 트램펄린에서 현재 평가기 프레임을 교체합니다. 그래서 자기 꼬리 재귀와 상호 꼬리 재귀는 논리 연속을 늘리지 않습니다.

언제 필요한가요?

루프를 재귀로 적는 편이 자연스러울 때 꼬리 호출이 중요해집니다. 재귀 호출이 마지막 동작이라면, 리스펙스는 연속을 하나 더 쌓는 대신 지금 연속을 교체할 수 있습니다.

실행으로 확인하기

LISPEX
(let loop ((n 10000) (acc 0)) (if (= n 0) acc (loop (- n 1) (+ acc 1))))

관측 결과

OUTPUT
10000

예제 읽기

이름 있는 letloop를 만듭니다. 각 분기는 acc를 돌려주거나, 더 작아진 n과 새 acc를 들고 곧바로 loop를 다시 부릅니다. 호출 뒤에 남아 있는 덧셈이 없습니다. 그래서 1만 번을 돌아도 논리적으로는 루프 하나로 끝납니다.

이 순서로 생각하세요

  • 꼬리 위치에는 마지막 본문과 if의 두 가지, 정규화된 cond·case, 마지막 and·or, do, call-with-values, apply가 들어갑니다.
  • 올바른 꼬리 동작이 말하는 것은 연속이 얼마나 자라느냐입니다. 실행 시간이 같다거나 무제한으로 실행된다는 뜻은 아닙니다.
  • 꼬리 재귀 프로그램에도 자원 한도는 그대로 적용됩니다. 이 한도는 결정적이고 프로필마다 다릅니다.

빠르게 고르기

형태꼬리 호출?이유
(if done? answer (loop next))선택한 분기 결과를 그대로 반환
(begin (display x) (loop next))호출이 마지막 폼
(+ x (loop next))아니요재귀 결과 뒤에 덧셈이 남음
(map loop items)콜백은 아니요map이 콜백 결과를 더 처리
꼬리 위치의 (apply loop args)apply가 호출자의 꼬리 위치를 보존

흔한 오해

비꼬리 재귀는 선언된 자원 한도에 도달할 수 있습니다.

현재 경계

  • 자원 오류가 깨끗하게 났다는 사실은 네이티브와 WASM의 임계값이 같다는 증거가 되지 않습니다.

다음으로

기저 사례와 누산기 변환은 재귀 가이드에서 익히세요. 꼬리 안전이 곧 무제한을 뜻하지 않는 이유는 결정성과 자원에서 설명합니다.

재귀 가이드 · 결정성과 자원