[LSP42] PikeとProcessing
(この記事はLISP Implementation Advent Calendar 23日目のためのエントリです。)
PikeとProcessingでLISPを作りました。
https://github.com/zick/PikeLisp
https://github.com/zick/ProcessingLisp
動機
今年の春、訳あって42個のプログラミング言語でLISP処理系を実装することになりました。これはその39〜40個目です。
Pikeはちょうどこのころネットニュースで「いまPikeが熱い!」みたいな記事が出てたので使うことにしました。
Processingは名前は知っていたものの明らかにLISPを作るのには不向きと思って使っていなかったんですが、「名前を知ってる言語は使ってしまえ」戦略により使うことにしました。
Pikeの思い出

さてここで問題です
Pikeの公式サイトを開いて初心者用のチュートリアルのページまで辿り着いてください。30秒以内に辿りつけた人は私より優秀なので、ぜひとも84個の言語でLISPを実装してください。
外観
Pikeは皆おなじみC-likeの文法です。
LObj nreverse(LObj lst) {
LObj ret = kNil;
while (consp(lst)) {
LObj tmp = lst.cdr;
lst.cdr = ret;
ret = lst;
lst = tmp;
}
return ret;
}
LObjは定義上スロットを持たないにもかかわらず、キャストもすること無く cdr にアクセスできます。
class LObj {
}
class Cons {
inherit LObj;
LObj car;
LObj cdr;
void create(LObj a, LObj d) { car = a; cdr = d; }
}
詳しくは調べてませんが、スロットの解決は実行時に行われるようです。そうなると、型を書くべきすべての場所に LObj と書くだけなので、実質的に型がないのと変わりません。コンパイル時に型をチェックしたい人には残念でしょうが私にとっては極めて楽でした。
_typeof
オブジェクトの型を比較する機能を探したんですが見つけることが出来ませんでした。代わりにオブジェクトの型を返す関数を見つけたので以下の様な方法で型を見ることに。
LObj kCons = Cons(kNil, kNil);
bool consp(LObj x) { return _typeof(x) == _typeof(kCons); }
まあ、動くんですけどなんだか微妙な感じに。
流行りの言語はやはり楽だった
冒頭に書いたとおり(当時)「いまPikeが熱い!」みたいな記事が出て、それなりに多くの人が反応していただけあって、Pikeは使いやすかったです。テキトーに書いてもなんだかよく分からないけど動く。Squirrel並みの速さでLISPを完成させることが出来ました。それ故に思い出が少ないです。
Processingの思い出

Processingといえばナウなヤングにバカウケな言語で、なんだかよく分からんけど視覚的にインパクトのあるチャラチャラしたプログラムを書くことに特化しているやつです。多分。でも今回はターミナルしか使いません。
標準入力なんてなかった
Processingの主な使用目的を考えたら当たり前のことなのですが、Processingには標準入力から文字列を読み込む機能なんてありません。幸い、Javaと連携する機能があるのでそれを使って標準入力から文字列をとってこようとしたのですが、コンパイルは通るもののなぜか上手く行かず。しかたがないのでLISPのプログラムはファイルから読み込むという方式に。これまでScratchを除くすべての言語で標準入力を使っていたので残念で仕方ありません。でもProcessingを使うのをやめて別の言語を探すほどの元気はなかったのでこの方式で逃げました。
外観
またしてもC-likeな文法です。
LObj nreverse(LObj lst) {
LObj ret = kNil;
while (lst.tag == CONS) {
LObj tmp = lst.cons().cdr;
lst.cons().cdr = ret;
ret = lst;
lst = tmp;
}
return ret;
}
次はLObjの定義を見てみましょう。
class LObj {
int tag;
Object data;
LObj(int t, Object o) {
tag = t;
data = o;
}
Integer num() { return (Integer)data; }
String str() { return (String)data; }
Cons cons() { return (Cons)data; }
Subr subr() { return (Subr)data; }
Expr expr() { return (Expr)data; }
...
}
私の過去の記事を読んでいた人はすぐに分かりますね。完全にJavaです。public とか private とか書かない分記述が短くなったJavaです。ひょっとしたらまったくJavaっぽくない書き方ができたのかもしれませんが、ようやく40個目の言語までたどり着き、少しでも早く42個の言語でLISPを書き終えたかった私は深く考えず、限りなくJavaに近い何かを書くことに専念しました。
小学生並みの感想
やはり、頭を使わずに書ける言語は素晴らしいと思いました。