最初の理由はvaluesプロシージャを使用して実行でき、2番目の理由はcase-lambdaを使用して実行できるため、継続渡しスタイルを使用する利点がわかりません。
values
...の定義が、複数の引数で継続を呼び出すことを指定していることを除いて。
継続渡しスタイルが役立つ問題の私のお気に入りの例は、パターンマッチャーを書くことです。case
これはステロイドのようなマクロの一種です。値を取り、その構造を、ペア、シンボル(変数を表す)、および非シンボルアトム(値を表す)から構築された一連のパターンと照合しようとします。一致が成功すると、パターン内の識別子が値の対応するサブパートにバインドされ、そのパターンの結果が実行されます。失敗した場合は、次のパターンを試行します。
この種のマクロを継続渡しスタイルの形式で記述するのは非常に簡単です。2つの異なる継続を使用して、「一致が成功した場合の対処方法」(成功の継続)と「一致が失敗した場合の対処方法」(失敗の場合)を表します。継続)。
私がかつて書いたパターンマッチングマクロのこの(簡略化された)フラグメントを取り上げます(構文ケースまたは構文ルールがわからない場合はお詫びします。その場で適応させたので、うまくいくことを願っています!)。ペアパターンに一致するルールに焦点を当てます。これは、ヘッドパターンとテールパターンの2つのパターンのペアで構成されるパターンです。頭が頭のパターンと一致し、尾が尾のパターンと一致するペアと一致します。
;;;
;;; Outer "driver" macro; the meat is in pmatch-expand-pattern.
;;;
(define-syntax pmatch
(syntax-rules ()
((pmatch value-expr (pattern . exprs) . clauses)
(let* ((value value-expr)
(try-next-clause
(lambda () (pmatch value . clauses))))
(pmatch-expand-pattern pattern
value
;; success-k
(begin . exprs)
;; failure-k
(try-next-clause))))))
(define-syntax pmatch-expand-pattern
(lambda (stx)
(syntax-case stx ()
;; Cases for constants and quoted symbols omitted, but they're trivial.
;; Match a pair pattern. Note that failure-k is expanded three times;
;; that's why pmatch encapsulates its expansion inside a thunk!
((pmatch-expand-pattern (head-pat . tail-pat) value success-k failure-k)
(syntax
(if (pair? value)
(pmatch-expand-pattern head-pat
(car value)
;; If we successfully match the head, then
;; the success continuation is a recursive
;; attempt to match the tail...
(pmatch-expand-pattern tail-pat
(cdr value)
success-k
failure-k)
failure-k))
failure-k))
;; Match an identifier pattern. Always succeeds, binds identifier
;; to value
((pmatch-expand-pattern identifier value success-k failure-k)
(identifier? (syntax identifier))
(syntax (let ((identifier value)) success-k)))
)))
pmatch-expand-pattern
マクロ式のsuccess-kおよびfailure-kサブフォームに注意してください。これらは、パターンマッチャーの「継続」として、少し緩い用語で使用されている式を表します。成功の継続は、検討中のパターンが検討中の値と一致する場合に使用されます。失敗の継続は、そうでない場合に使用されます。成功の継続は、現在の最上位パターンのすべてにまだ一致したかどうかに応じて、パターンの残りの部分に一致する式か、パターンの一致が完了したときに実行する結果のいずれかになります。失敗の継続は、パターンが一致しない場合に、次の選択ポイントに戻るために使用されます。
前述したように、「継続」という用語は、式を継続として使用しているため、上記のコードでは少し緩く使用されています。ただし、これは、これをマクロとして実装する方法の詳細にすぎません。アルゴリズムは、実際の手順を継続して、実行時に純粋に実装できます。(また、try-next-clause
手順は文字通りの意味での継続です。)