スライドはこちらです.

また, 当日 Ustream で配信された動画はこちらにアーカイブされています.
動画中の一番最初がボクの発表です.
Lightning Talk

この LT では DSL のサンプルとして Paml というテンプレートエンジンを紹介しています.
また, オチとして, [] で DSL だけじゃなく汎用言語も実装できる, ということで PHP で実装された Lisp ライクな言語 LisPHP を紹介しています.

いずれも GitHub にリポジトリを公開しているので, 興味のある方はご覧ください.

結構ネタ的な要素も強いのですが, この発表でボクが割と真面目に主張したかったのは以下の点です.

  1. PHP 5.4 では [] が配列リテラルとして導入された
  2. PHP の array は他の言語と比べて特殊なデータ構造である
  3. その特性を DSL 的に活用することができる

スライドのまとめと若干表現が違っていますが, 大筋は変わりありません.

LT の 5 分間ではこれらについて説明しきれなかった部分があるので, この記事で補足しようと思います.

(なお, 同カンファレンスで他の方の発表を聞いての感想などは改めて別の記事に書くつもりです.)

1. PHP 5.4 では [] が配列リテラルとして導入された

特にこれ以上の説明は必要ないとは思いますが, 念のため.

今までは配列を以下のように記述していましたが,

PHP 5.4 alpha 3 以降からは以下のように置き換えることができます.

見ての通り, array()[] に置き換えることができるようになった, というだけで機能的な変化はありません.

いわゆる Lightweight Language はその多くが配列リテラルとして [] を採用していますが, PHP では長らく使用することができませんでした.
パッチを送った @rsky さんを始めとする開発者の皆様のおかげでようやく使用することができるようになったので, 感謝をもって使用しましょう.

2. PHP の array は他の言語と比べて特殊なデータ構造である

これはスライド中でもそのまま説明していますが, PHP が持つ特徴として, 配列とハッシュに区別が無い, ということが挙げられます.
PHP における array は配列っぽさとハッシュっぽさを持った, 特殊なデータ構造であり, それらを混合して記述することができてしまいます.

これもスライド中で紹介していますが, PHP では以下のような記述が問題なく通ります.

そしてこちらはスライド中に一度入れて後に割愛したものですが, 要素の順序を入れ替えたらどうなるか.

表示上の順序こそ記述した通りの順番に変わっていますが, 集合としては等しい値であることがわかります.
0 番目の要素のあとに foo という要素を追加して, さらにもう一つ要素を追加しても, その要素には添字として 1 が割り当てられます.

3. その特性を DSL 的に活用することができる

これらを踏まえて, [] で奇妙なデータ構造を記述して, DSL っぽく活用することを思いつきました.

いきなりですが, スライドで紹介したテンプレートエンジン Paml を例に出します.
Paml には REPL (インタラクティブシェル) が同梱されており, Paml のコードを HTML に変換して出力することができます.

入力としての Paml (まぁ配列なんですが) の要素は順番が入れ替わっていますが, 出力はいずれも同じになっています.

もちろん, プログラムがそういう実装になっているというのもありますが, 前提としてこの 2 つの配列は集合として等しい, ということが重要です.

実装の詳細としては, この配列とハッシュが混合したデータ構造から, 配列とハッシュをそれぞれ取り出してから処理するようになっています.

スライドでは, より現実的なフレームワークへの応用として, モデル定義の記述に活用することを提案しています.

例えば, phpDataMapper (なんかここ数日アクセスできない状態ですが) という O/R マッパーのモデル定義は以下のようになっていますが,

これを以下のようにしてみてはどうか, ということです.

違いとしては, array() の代わりに [] を使っているのもそうですが, 後者ではデータ型の指定時の type という添字を使っていません.

イメージとしては, 第一引数に型名を指定して, そのあとにはさらなるオプションがキーワード引数として指定できる, といったような感じです.
型名はどのカラムにも指定する必要で省略不可能なので第一引数としていますが, 後は全てオプションなのでキーワード引数にする, といった具合です.

おまけ: LisPHP の紹介

スライド上ではコードとその出力を出しただけですが, ちゃんと実装しています.
以下は円周率 PI と円の面積を計算する関数を定義し, 実際に計算する例です.

その他, examples ディレクトリには LisPHP のサンプルコードもあります.
フィボナッチ数列による再帰の例 (スライドに掲載したものです) もあるので, ご興味のある方は是非.

LisPHP の特徴は以下の通りです.

  • PHP の array をコードとして扱う (code as data)
  • PurePHP で記述されている (ただし, PHP 5.4 alpha3 以降が必要)
  • 同梱の REPL とインタプリタは PHP の eval を利用することで字句解析も構文解析も PHP まかせ

実はこれにも元ネタがあって, 元は Python で書かれた Lispy というものです.
こちらは string.split とかで超お手軽に字句解析・構文解析はしていますが.

((Pythonで) 書く (Lisp) インタプリタ

発表時, スクリーン上に LisPHP のことが出ていたのはたったの 5 秒間でしたが, 思いのほか笑いを取れて満足しています.
同カンファレンスにスピーカーとして来日していた方にもウケていたとのことで, 発表前日夜に思いついて, 5 時間ぐらいかけて実装した甲斐があったというものです.
(逆に Paml へのリアクションは思いのほか薄かった. これもネタだったのに)

まとめ

人前で LT をやるのは初めてで, とても緊張しましたが, とりあえずは満足する形で終えることが出来て良かったです.
素晴らしい機会をくださった PHP カンファレンス 2011 実行委員会の皆様, そして会場で聞いてくださった皆様に感謝致します.

なお, 次回があれば 30 分ぐらいで現場の役に立つ話がしたいと思っているので, 来年以降の開催も楽しみにしています.

, , ,

最近 .htaccess をいじることが多いんですが, 融通効かないなと思うことが多々あります.

.htaccess を Ruby で書くことができれば… ということでとりあえずプロトタイプ程度ですが作ってみました.

DSL の記述例

これが以下のように出力されます.

<IfModule mod_rewrite.c>
  RewriteEngine on
  <Limit GET>
    RewriteRule ^/user/(.*)$ /user.cgi?id=$1 [L,R]
  </Limit>
</IfModule>
Order Deny,Allow
Deny from All
Allow from 192.168.0.11
Allow from 192.168.0.12
Allow from 192.168.0.13
Allow from 192.168.0.14
Allow from 192.168.0.15

この .htaccess 自体はあまり気にしないでください.
DSL の構文を紹介するために適当に書いてます.

この DSL を実行するのに必要なプログラム, 使い方は以下の Gist をご覧ください.
DSL to write .htaccess files.

特徴

  • Ruby で書ける
    Ruby なので, Range オブジェクトや, その each メソッドを用いて, ループが書けます.
  • あらゆるディレクティブをメソッドとして記述できる
    RewriteEngine や Order といったディレクティブは, 引数をひとつ受けるメソッドとして実行されます.
    内部的には, method_missing で処理されています.
  • Ruby のコードブロックが使える
    上記の例でいう IfModule メソッドのようにブロック引数を渡すと, <IfModule> ~ </IfModule> というように出力されます.
    また, ブロックのネストにも対応しています.

あくまでもプロトタイプなので, 全然実用レベルでは無いですが, 洗練させればなかなかおもしろいものになるんでしょうか.

DSL を作るためのノウハウが足りないので, いいアイディアをお持ちの方は, 是非 @yuya_takeyama まで教えてください.
とりあえずは dsl { ~~~ } を省略できるようにしたい…