Diary?

2009-10-31
Sat

(17:10)

昨日の BPStudy で使ったスライドを公開。といっても昨日やったことで価値のある部分って俺と檜山さんがアドリブで喋ったり質疑応答で答えたりした部分だと思うので、スライドだけ見ても何が何やらかもしんないけど。

というわけで、昨日の質疑応答では話がこんがらがるのであえて喋らなかったことをいくつか。


Caty テンプレートは常にプレースホルダーへの入力はエスケープされるので、もしも Wiki の本文の出力などを行うときは {$wiki|noescape} などとエスケープさせないためのフィルターの指定を行わなければならない。なので、もしもこれを忘れたら表示が崩れてしまうのでは? そういったプレゼンテーションロジックは分離できないか? といった質問が出た。あの場では説明しなかったが、実はこの部分はある手段を用いて分離可能である。

仮に {$wiki} というプレースホルダーだけを持つテンプレートに値を入れるなら、そおテンプレートを出力するコマンドは object{"wiki": string} -> string という型を持っていることになる(実際、次の次あたりのリリースで print コマンドは多相型になるのでこの通りの動作となる)。そして string 自身にはたいした情報がないのでそれが HTML エスケープされるべきか否かはテンプレートの書き手が判断するしかない。なので、ここに更なる情報を付け加えられるならエスケープ処理はテンプレート本体から分離できることになる。

昨日のデモで何度かやったが、 Caty スクリプトにはアノテーションタグの機能がある。

type person = @person object {
    "name": string,
    "age": integer
};

上記の型は object 型ではなく @person object 型となり、厳密に object 型とは区別される。同じようにスカラー型にもタグは付加できるので、例えば以下のような型を作ることができる。

type htmlString = @html string;

そしてテンプレートエンジン側に htmlString 型はエスケープしない、という事前の了解があるのなら、 HTML エスケープのプレゼンテーションロジックはテンプレート内部から分離できることになる。これは Terrence Parr の主張における Renderer を切り替えることで

  • デフォルトは htmlString をエスケープ
  • オプションで単に htmlString から string を取り出して表示

という事が簡単に行える。

このアイディアは一見悪くなく思えるが(いや実際悪くないんだが)、そもそもタグ機能はユーザーが(組み込み型の名前とバッティングしなければ)自由に定義できる事を前提にしているので、そこにシステムから「このタグ使っちゃダメ」を入れ込むというのは理念的に問題がある。何より一つでもこのような措置を認めてしまうと、「○○のためにシステムレベルで使うタグ××を定義しましょう」という話がいくらでも出てくる恐れが十分にある。

ただし、もしも十分に議論を練った上で本当に普遍的なシステムレベルのタグセットを定義して、それに関する規約が明文化できるなら、別にこのやり方を否定するつもりはない。例えばタグ名を _ で始めるのは特殊な用途のタグ名だという事にして、

type htmlString = @_html string;

という形で記述する事にし、特殊タグは事前に定義したシステムレベルのものだけをみとめ、また特殊タグは直接書かせないで htmlString などの名前付き型で使わせる、といった運用ができるのであれば、この部分のプレゼンテーションロジックは隠蔽できる。万が一コマンドの書き手が htmlString ではなく string を出力しても、デフォルトがエスケープモードで安全側に倒されているので問題はない。また、このやり方の場合 string と htmlString は別の型なので、コマンドレベルで見ても HTML 文字列をよくわかんないまま文字列操作してぶっ壊れるなんてことはなくなる(型エラーになる)。

というわけで、このやり方は検討する価値がある。最初に思いついた時はテンプレートエンジンが Caty の拡張 JSON に依存するのが嫌だったが(単体テスト困難になる)、テスト用にはそのあたりと切り離された Renderer を DI すればいいので実はどうにかなる(当初は Renderer が分離していなかった)。ただし優先順位的に微妙な問題なので、いつ手を付けるかは不明。


実は水曜日にやったリハーサルでも「Caty を RPC サーバに」みたいな話は出てきて、確かに Caty には単なる Web アプリケーションフレームワーク以上のポテンシャルはある。が、それはあくまでも副次的な結果に過ぎないと思う。

昨日喋った通り Caty の目的はスキルの有無に関わらず真っ当な開発スタイルによる安全・安心なサイト構築の手段を提供するというもので、だから学習容易性だの単純性だのにこだわっているわけ。そしてその目的をきちんと達成するためにはそれ相応の理論基盤が必要だし、そもそも真っ当なソフトウェアの作りをすると大抵がフロントエンド+言語処理系+ドライバ・システムコールみたいな設計に近づく。多くの場合は言語処理系が抽象 API 層か DSL かなにかで代用されてるけど、ちょっと Caty の場合は事情が違うから本物の言語処理系が乗ってるってだけ。そうやって設計・構築されたソフトウェアが普遍性を持つのは当たり前で、だから Web とコンソールが対等だし GUI を被せるのも全然問題ないわけ。当然、 RPC サーバにしたって問題はない。

実は Caty ってトリッキーでも斬新でも何でもなくて、スクリプトエンジンとその他の部分の関係はシェルスクリプトとターミナルとバックにある OS のシステムコールとディスプレイドライバなどのドライバだったりするし、サイトの構造も ~/public_html, ~/cgi-bin, ~/bin みたいな構造だし、本当に昔からある技術の延長線上であって突然出てきたキメラなんかじゃない。

多分一番衝撃を与えたであろう Caty スクリプトと JSON スキーマも、ちゃんとした理論的な背景があってああなっているのであって、別に適当ぶっこいてやってるわけじゃない。その理論を理解するにはいろいろ手間入り物入りだが、まともなソフトウェアを作ろうとするのにろくすっぽ勉強しないでコードだけ書いてる方がよっぽどおかしいので、極めて真っ当な状況だともいえる。


とかいう事を考えてる暇があったら、俺は Caty スクリプトのコンパイラと VM の設計をとっととやるべきなんだが。あと型推論アルゴリズムの実装。


追記:まずユーザに勘付かれはしないだろうけど、 Caty スクリプトにはモナドあるよ(定式化の道具に使ってるって意味で)。それについては檜山さんがそのうち何か説明するでしょう。で、こういう事を書くと「Caty スクリプトってすごい言語なんじゃないの?」と思われるかもしれないけど、マジで Caty スクリプトはしょぼい機能しかないんだって。覚えることなんてろくにないし、そもそもベター JSON として使うところから始められるんだって。


追記:発表の最中に「Caty コマンド宣言で Python による実装だけでなくて Caty スクリプトによる実装もコマンドの実装手段として使おう」という檜山さんの提案を鬼反応で却下したわけだが、その理由を今から説明する。

まず Caty のコマンド宣言は以下のようになっている。

command length :: array [_T] -> integer
                  refers python:util.Length;

ここでは util モジュールの Length クラスを length コマンドの実装で使っているという宣言になる。これと同様に、 Caty スクリプトもコマンド宣言で使いたいというのが檜山さんの要望。

command foo :: string -> string
               refers caty:foo.caty

これはダメだ。なぜなら、 foo.caty の中身がこうなっていたら無限再帰に陥るからだ。

foo

ちなみに foo.caty の中身がこうなっているのは合法。

foo.caty

何故かというと、 Caty スクリプト内部で別のスクリプトファイルを呼び出すのはコード展開の形式で実装しているので(C の #include に近い)、スクリプト呼び出しが再帰的な場合はそもそもコンパイルができなくなっている。

普通のユーザが使う場合は、スクリプトのコンパイル結果がコマンドの実装のバグを除けば常に有限の実行ステップで終了するのが Caty スクリプトの要件なので、それを叩き壊すような機能は入れるわけにはいかない。

まあ、俺もユーザ定義関手と高階関数文法を却下されてるんだがな。

Creative Commons
この怪文書はクリエイティブ・コモンズ・ライセンスの元でライセンスされています。引用した文章など Kuwata Chikara に著作権のないものについては、それらの著作権保持者に帰属します。