Inverting back the inversion of control or, Continuations versus page-centric programming, Christian Queinnec, (2)

いまさらですが、前回の続き。

本題の、継続を使ってどのようにクライアントの状態を楽に保存するか、という話です。
本論文に書いてある簡単な例を見てみましょう。二つの値を入力させて、それらの和を求めるようなwebアプリケーションです。


(define n1 0)
(set! n1 (read-first-number))
(display-result-page n1 (read-second-number n1))

read-first-numberは一つ目の値を入力するためのフォームを生成し、そのフォームに入力された値を返す関数、read-second-numberは二つ目の値を入力するためのフォームを生成し、そのフォームに入力された値を返す関数だとします(ここで引数としてn1を渡しているのは、一つ目の値として入力された値を、二つ目の値を入力するページで表示するために使っているだけのようです)。そして、display-result-pageという関数は、二つの値を受け取って、それらの和を表示するための関数です。
前も書いたようにある式の継続とは、「その式が実行された後の環境における、その後の残りの計算」を表しています。よって、read-first-numberを呼んだ後の継続というのは、以下のような形になります。


(set! n1 ???)
(display-result-page n1 (read-second-number n1))

ここで、???はread-first-numberの戻り値を表しています。仮にread-first-numberの戻り値として123が帰ってきた場合、read-second-numberの呼出し後の継続は


(display-result-page n1 ???) | n1 = 123

ここで、|より右の部分は、その時の環境を表しています。Schemeでは、継続はラムダ記法で


(lambda (n2) (display-result-page n1 n2)) | n1 = 123

と表現されます。このように状態を持った関数の事をクロージャといいます。
ここまでくると、だんだんわかってくると思いますが、この論文では、ユーザからの入力が必要となるようなフォームを表示する場合、そのページを出力するだけでなく、その時点での継続を保存します。そして、submitボタン(もしくはリンク)にその継続を呼び出すようなURLを結びつける、ということをやっています。
そうすると、継続の中にそれまでの状態とこれから行うべき処理が含まれているので、セッションにデータを入れたりする必要が無くなる、というわけなのです。

そして、read-second-numberはSchemeでは以下のように実装することが出来ます。


(define (read-second-number n1)
(define (html-generator kUrl)
(html (head (title "SumServlet")
(body (form method: 'post action: kUrl
(table (tr (td) (td n1))
(tr (td "+") (td (input type: 'text size: 10 name: "n2"))))
(input type: 'submit
value: "SUM?" )))))
(let ((httpRequest (show html-generator)))
(string->number (get-request-parameter httpRequest "n2"))))
ここでキモになるのがshowという関数です。


(define (show html-generator)
(call/cc
(lambda (k)
(display (html-generator (k->url k))
(current-connection))
(close-output-port (current-connection))
(suicide))))
call/ccは、呼ばれた時点での継続をkに渡します。そして、k->urlという関数は継続をURLに変換するための関数とします。そうすると、URLとしてshowが呼ばれた時点での継続がURLの形式で渡され、そのURLがフォームを送信する先となるのです。
こうしてしまえば、サーバはこのコネクションをきってしまいます。
そして最後にリクエストを受け取るサーバプロセスを定義します。ここでは簡単のため、一つのスレッド上で動くとしています。

(define (server httpRequest)
(let ((url (get-request-url httpRequest)))
(let ((k (url->k url)))
(if k
(k httpRequest)
(error "lost continuation" url)))))
ここでは、リクエストのURLを見て、それに対応する継続が存在すればその継続を実行し、無ければエラーを出力しているだけです。

showやserverといった関数は汎用的なものなので、アプリケーションの開発者はアプリケーションの全体の流れ(一番最初のプログラム)と、その中でフォームを生成する関数を定義してあげれば良い、ということになります。
こうすることで、クライアントの状態を監視するのに面倒なセッション管理を行う必要が無くなります。

本論文には、他にも一回だけしかsubmitしたくない場合も簡単に実装できるよ、とかフォームの結果を検証するのも簡単に出来るよ、とか面白い話が書いてあります。

この論文、書いてある内容もわかりやすいのだが、継続の説明がかなりわかりやすい気がする。沢山例を使っているので、実感として継続が何のためのものなのか、わかりやすい。
なので、継続を勉強したいとか言う場合にも読むといいんじゃないかな、と思ったりした.

Inverting back the inversion of control or, Continuations versus page-centric programming, Christian Queinnec, (1)

継続(continuation)を用いてwebプログラミングをすると、これまでの開発手法よりも従来のアプリケーション開発に近いスタイルで行うことができるようになるよ、というお話。
そもそも、なんでwebアプリケーションの開発が面倒になるかというと、以下の様な理由があるという。

  • HTTP自体はステートレスなので、クライアントとサーバが何度もやり取りを行うようなアプリケーションの場合、クライアントの状態を保持するのに、セッションを使うなどしないといけない。これが複雑で面倒である。
  • クライアント(ようはブラウザ)側の「戻る」ボタンや新しいウィンドウ・タブを使うことによって、すでに入力された値を再度入力することが出来てしまう。例えば、ショッピングサイトでの注文ボタンの二度押しなど。これに対処しないといけない。

こういった問題から、開発者を解放するのが継続を使った開発*1なのだという。
継続そのものについては、そこいらにいい紹介があると思うので、深く突っ込みはしないが、簡単に言うと、「プログラム中のある時点で、それ以降行わないといけない処理」のこと。例えば、継続をファーストクラスで扱うことの出来る言語としてはSchemeが真っ先に思いつくと思うけど、Schemeでは継続は一つの関数として扱えるようになっている。
これだけだと良くわかんないと思うので、

あたりを見ると、大体イメージできるかもしれません。特に二つ目一つ目の川合史郎さんによる解説がわかりやすかったです。
それで、この継続とwebアプリケーションがどう関係してくるのかという話に移ります。
最初に言ったように、webアプリケーション開発において面倒なことは、クライアントの状態を保存することです。なので、クライアントの状態を容易に扱うことが出来れば、ローカルで動かすインタラクティブなアプリケーションと同じように開発を行うことができるようになるだろう、というのがこの論文の趣旨です。そしてそのクライアントの状態を、継続を使って表してあげましょうという事です。
[続きはここで]

*1:というかCPS

マルドゥック•ベロシティ

マルドゥック・ヴェロシティ〈1〉 (ハヤカワ文庫JA)

マルドゥック・ヴェロシティ〈1〉 (ハヤカワ文庫JA)

いかんいかんと思いつつ、買っちゃった。
うーん、困った、面白いよう。
まだ、一巻の途中なんだけど、ほんと止まらない。
何となく、サーボーグ009とメタルギアソリッドを彷彿とさせるような感じ。話の中で出てくる重要な法案も09条だし。
関係ないか。

とりあえず、全部読みます。

あれれ??

今、ブラウザを立ち上げて、はてなアンテナ見ようと思って、ツールバーからアンテナのボタン押したらなんか全然知らないページがずらっと表示される。
あら、こんなページ、アンテナに追加してたっけ??とか思っていたら、ページのヘッダの部分が「ようこそ、○○○(YuichiTanakaではない)さん」となっている。え?!?!?
普通に管理画面とかも入れちゃうんですが。。。(もちろんいたずらはしてませんよ)
これってなんで????こっちの問題かしら。

Django Book

The Definitive Guide to Django: Web Development Done Right (Expert's Voice in Web Development)

The Definitive Guide to Django: Web Development Done Right (Expert's Voice in Web Development)

Amazonをちらちら見てたら、来年の春にDjangoの本が発売されるのを発見。まだ結構先だぁ、とか思ってたら、オンラインでβ版が公開されてました!(ただし、途中までしかない。。)
公開されてる事も素晴らしいんだけど、このβ版では、文章中の好きなところにコメントをつける事が出来るようになっていて、かっこいい。これだと、フィードバック得やすいし、見やすいね。

同でもいいことだけど、今日、学校の構内で、ウェディングドレスを着た外人のおばちゃんと、白いタキシードを着た外人のおっちゃんのカップルが口論しながら歩いていた。
結婚式場と間違えたのだろうか。

IPython

最近、pythonにはまっている。
IPython便利だよーー。今までは、ふつうにコンソールでIDLE使ってたんだけど、IPythonみっけて使ってみてからは、もう絶対IDLEには戻れない。ちょっと行間がすかすかになっちゃって一画面の情報量が少なくなってしまうのがいやなんだけどね。
でも、これは使うべき。
特に、オブジェクトの後ろに?をつけると、そのオブジェクトの情報を表示してくれるのが、かなりうれしい。結構使い始めだから、どのオブジェクトがなんだったか忘れちゃう事が多いんだけど、これがあればもう大丈夫。pythonではクラスとか関数とか全てがオブジェクトなので何でも?をつければ見れちゃうし。こういうのあるとdocstringも効いてくるなぁ。