何故作ったし
みくった〜♪を柔軟に拡張できるようにするため
文法
S式とM式を合わせたような文法を採用。略してSMs(ry
だけど見た目はあんまりLispっぽくない。これは、できればプログラマでなくても多少使えるように、などいろいろ考えがある。以下に、みくった〜♪のフレンドタイムラインプラグインのコードを示す。
tl = gen-timeline[200]
regist-window[tl]
onupdate << { (watch msg)
add[tl msg]
}
Lispなんて言わなければ良かった(笑)S式だけで書くと以下のようになるだろう。
(setq tl (gen_timeline 200))
(regist-window tl)
(add onupdate (lambda (watch msg) (add tl msg)))
まず、特記事項はM式だ。これは、S[...]と表記し、(S ...)というリストに展開される。一般的な言語の関数呼び出しf(x)に近い書き方ができるし、S式に慣れていなくても比較的コードが見やすくなる。
次に、演算子。通常Lispでは計算式を次のように書く。
(+ 1 2 3)
いわゆる前置記法でとっつきにくい。演算子がリストの最初以外に現れた場合、その前後の値を括弧で括り、第一要素と演算子を入れ替える。文章では説明しづらいが、要するにパース時に要素の入れ替えが発生するというものだ。
例えば、
1 + 2 + 3
A B + C D
1 + 2 * 3 - 4
は、
(+(+ 1 2) 3)
(A (+ B C) D)
(+ 1 (- (*2 3) 4))
となる。
最後に中括弧だが、これはlambdaの省略記法。
(lambda (a b) (+ (* a a) (sqrt b)))
は、
{(a b) a * a + sqrt[b] }
と書ける。また、シンボル_は、その関数が呼ばれた時の引数リスト、_nのように数字をつければ、n個目の引数に束縛されている。普通の用途ならこれは不要かと思ったが、フィルタを書くために多用することになるので、あえて用意した。
フィルタ関数
では、本題のフィルタにうつる。たとえば、幾つかの優秀なツイッタークライアントでは、「ユーザaか、aへのリプライか、googleが含まれている」つぶやきだけを抽出したタブを作成できるが、これはこう書ける。
{ ()
or{
(assoc[_0 'user] == "a")
include?[assoc[_o 'message] "@a"]
include?[assoc[_o 'message] "google"]
include?[assoc[_o 'message] "@a"]
include?[assoc[_o 'message] "google"]
}
}
(※注:orは引数をtが帰ってくるまで順次実行するマクロだが、はつねLispでは表記上の理由からlambdaも渡せる)
ちょっと複雑だ。Rubyだとこうなるだろう。
lambda{ |m|
ちょっと複雑だ。Rubyだとこうなるだろう。
lambda{ |m|
m[:user] == 'a' or
m[:message].include?("@a") or
m[:message].include?("google")
}
あれ、かわんない。無理もない。はつねLispの関数は、以下の値のいずれかになる。
あれ、かわんない。無理もない。はつねLispの関数は、以下の値のいずれかになる。
- =演算子でオーバライドされた関数
- はつねLispで定義されたプリミティブ関数
- 第一引数のクラスのメソッド
- 同名のRuby関数
例えばchomp[string]は、Rubyでstring.chompと書くのと同じ意味だ。しかしながら定数にはアクセス出来ないので、例えばnew[Time]のようなことはできない。これはあえて入れた制約で、これによって例えばはつねLispをJavaScriptなどで再実装する場合に、String, Numeric, Listくらいを再実装するだけではつねLispがすべて動かせるようになる。
また、はつねLispはほぼRubyに直訳出来る。プリミティブ関数も短いRubyコードだし、何よりほかのメソッド呼び出しは全てRubyのそれだからだ。つまり、高速化のためにRubyのコードに翻訳することが出来るのだ。
いわば、マクロを使えるようにしたRuby、という感じなのかもしれない。当然、Rubyとちがって全てS式にできるというのが最大のメリットだが。
0 件のコメント:
コメントを投稿