R6RS:翻訳:R6RS:11.20 Tail calls and tail contexts
11.20 末尾呼び出しと末尾文脈
末尾呼び出しとは末尾文脈に現れる手続き呼び出しのことである。末尾文脈は帰納的に定義される。末尾文脈は常に特定の lambda 式について決定されることに注意。
- lambda 式の本体部分の最後の式の、下 <tail expression> で示してある部分は末尾文脈である。 (lambda <formals> <definition>* <expression>* <tail expression>)
- 以下の式のひとつが末尾文脈にある場合、 <tail expression> で示されている部分式は末尾文脈である。これらは本章で述べたフォームの文法仕様のうち、 <expression> のいくつかを <tail expression> で置き換えることにより派生したものである。末尾文脈を含む規則だけをここに示す。
(if <expression> <tail expression> <tail expression>) (if <expression> <tail expression>) (cond <cond clause>+) (cond <cond clause>* (else <tail sequence>)) (case <expression> <case clause>+) (case <expression> <case clause>* (else <tail sequence>)) (and <expression>* <tail expression>) (or <expression>* <tail expression>) (let <bindings> <tail body>) (let <variable> <bindings> <tail body>) (let* <bindings> <tail body>) (letrec* <bindings> <tail body>) (letrec <bindings> <tail body>) (let-values <mv-bindings> <tail body>) (let*-values <mv-bindings> <tail body>) (let-syntax <bindings> <tail body>) (letrec-syntax <bindings> <tail body>) (begin <tail sequence>)
- <cond clause> は (<test> <tail sequence>) である。
- <case clause> は ((<datum>*) <tail sequence>) である。
- <tail body> は <definition>* <tail sequence> である。
- そして、 <tail sequence> は <expression>* <tail expression> である。
- cond 式が末尾文脈にあり、 (<expression1> => <expression2>) 形式の節を持ち、 <expression2> の評価結果の手続きへの(暗黙の)呼び出しは末尾文脈内にある。 <expression2> 自体は末尾文脈内にない。
特定の組み込み手続きもまた末尾呼び出しを行なわなければならない。 apply と call-with-current-continuation の第一引き数、 call-with-values に渡された第二引き数も、末尾呼び出しで呼び出されなければならない。
次の例では f への呼び出しだけが末尾呼び出しである。 g や h への呼び出しは末尾呼び出しではない。 x への参照は末尾文脈内にあるが、呼び出しではないため、末尾呼び出しではない。
(lambda () (if (g) (let ((x (h))) x) (and (g) (f))))
注: 上の例の h への呼び出しのような非末尾呼び出しを認識できる処理系は、それが末尾呼び出しであるかのように評価することができる。上の例では、 let 式は h への末尾呼び出しへと翻訳できる(h が期待しない個数の値を返す可能性は無視できる。なぜなら、その場合 let の効果は未規定であると明示されてい、実装系依存だからである)。