スキップしてメイン コンテンツに移動

投稿

ラベル(lisp)が付いた投稿を表示しています

部分継続チュートリアル

この文書について これは Community Scheme Wiki で公開されている composable-continuations-tutorial (2010年09月30日版)の日本語訳です。 誤字脱字・誤訳などがありましたらコメントあるいはメールで御指摘いただけると幸いです。 本訳は原文のライセンスに基づき Creative Commons Attribution-ShareAlike 2.0 Generic の下で公開されます。 Original text: Copyright© 2006-2010 Community Scheme Wiki Japanese translation: Copyright© 2011 SATOH Koichi 本文 部分継続(Composable continuation)は継続区間を具象化することで制御を逆転させるものです。 ウンザリするほど複雑な概念を表す長ったらしいジャーゴンのように聞こえますが、実際はそうではありません。今からそれを説明します。 reset と shift という2つのスペシャルフォームを導入するところから始めましょう [1] 。 (reset expression) は特別な継続を作るなりスタックに目印を付けるなりしてから expression を評価します。簡単に言えば、 expression が評価されるとき、あとから参照できる評価中の情報が存在するということです。 実際には shift がこの情報を参照します。 (shift variable expression) は目印のついた場所、つまり reset を使った場所にジャンプし、その場所から shift を呼び出した場所までのプログラムの断片を保存します; これはプログラムの区間を「部分継続」として知られる組み合わせ可能な手続きに具象化し、この手続きに variable を束縛してから expression を評価します。 組み合わせ可能(Composable)という語はその手続きが呼び出し元に戻ってくるため、他の手続きと組み合わせられることから来ています。 Composable continuationの別名として例えば限定継続(Delimited continuation)や部分...

Schemeでカリー化

Haskellの有名な特徴として、関数が勝手に カリー化 されるという点があります。 要するにHaskellの関数は常に部分適用可能になっていて、 f foo bar baz という関数適用は (((f foo) bar) baz) と解釈されています。これは非常に強力な機能で、汎用的な関数を目的に合わせて簡単に特殊化することができます。 Schemeやその他のLispでは、引数は必ず同時に与えないといけないので、カリー化したものを作ろうとするとクロージャを使って (define f (lambda (x) (lambda (y) (lambda (z) ...)))) とでもしなければなりません。しかも呼び出すときには (((f foo) bar) baz) と、1つずつ順番に適用する必要があります。 私が欲しいのは、"(Haskellが透過的にやっているように)与えられた引数を先頭から順に束縛し、足りない分を引数とするクロージャを返す"ような関数です。 ((f foo) bar baz) だろうが (f foo bar baz) だろうが (((f foo) bar) baz) だろうが同じ結果を返す関数を作りたいわけです。そこで、カリー化関数を作成するマクロを書きました。 (define-syntax curry (syntax-rules () ((_ (arg0) body ...) (lambda (arg0) body ...)) ((_ (arg0 arg1 ...) body ...) (lambda (arg0 . rest) (define applied (curry (arg1 ...) body ...)) (if (null? rest) applied (apply applied rest)))))) このマクロを使って作成した関数は、引数を先頭から束縛していき、すべての引数が揃ったときに値を返します。 (define greet (curry (when who) (display (string-append "...