末尾呼び出しとは末尾文脈に現れる手続き呼び出しのことである。末尾文脈は帰納的に定義される。末尾文脈は常に特定の lambda 式について決定されることに注意。
(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>)
特定の組み込み手続きもまた末尾呼び出しを行なわなければならない。 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 の効果は未規定であると明示されてい、実装系依存だからである)。