美しいループ記法求む!


いま私は速度的に特化したプログラムを書かなくてはいけない。1%でも速いほうが望ましい。必然的に言語はC/C++となる。しかし、いまさらC/C++なんか使いたくない。もう少し洗練された記法が使える言語が好ましい。


なければ作ればいいやと思い、丸一日かけてC++のparserをC#で書いた。
C++風言語の字句解析と構文解析は出来るようになった。(C++ templateは除く。)


あとは、いかようにも文法を拡張できる。この言語を仮にいまYaneCと名付ける。YaneCはコンパイルするとC++のコードを生成する。


それでいま悩んでいるのがループ記法だ。C#のようなforeachが欲しい。最初、次のように書けるようにした。

foreach var x in vect
	sum += x;

ふむ、C#っぽくていい感じだ。C/C++のdefineマクロでforeachみたいなのを作ると次のようなものになるが、この末尾の");"を私は生理的に受け付けない。

foreach(x,vect,{
	sum += x;
});

次に範囲型という型を作って".."で書けるようにした。

foreach i in 0..9
	sum += i;

まあ悪くはない。N回まわるならどう書くか?

foreach i in 1..N
	sum += i;

ループがzero originではないのは嫌だ。0からだろう。

foreach i in 0..N-1
	sum += i;

なんだこの"-1"というダサさ。これだと普通のforのほうがよっぽどマシだ。そもそも範囲型でExpression(式)をとれるようにしてしまうと、次のように書いたとき、"1"のあとの"*"を掛け算だと認識して次の行もExpressionとして捉えてしまうんだよ。

foreach i in 0..N-1
	*sum += i;

Cのポインタ記法が憎い。YaneCではC/C++のポインタ記法を禁止してもいいが、過去のソースとの互換がとれないのも嫌だ。

これを回避するためには、foreachの行末の改行をセパレータとして認識するようにするか、次ように"{"〜"}"でくくる記法にするしかない。行末の改行をセパレータと認識するようにすると、フリーフォーマットではなくなってしまう。それは少し嫌だ。だとすると後者か?

foreach i in 0..N-1
{
	*sum += i;
}

一気にダサくなった。げんなりである。すでに普通のforが恋しい。普通のforなら(C#なら)code snippetが使える。苦労してC++ parserまで書いて、状況は悪化している。やるせない。N回まわるのは、Rubyっぽく次のように書けばどうか。

N.times 
	printf( "こんにちは" );

こう書くには、integer型に対するstatic methodを定義できれば良い。こんなことは1時間もあれば楽勝だ。さっそく私はinteger型のstatic methodを書けるように拡張した。でもよく考えたら、ループ変数が欲しいこともある。Rubyに倣って次のように書けるようにするか?

N.times 
{ |i|
	sum += i;
}

なんだこれ。一気にダサくなった。おいおい勘弁してくれ。私は'{'とか'}'が大嫌いなんだよ。ループ内の処理を1行書きたいだけなのに、'{'で'}'囲って行数がだらだらと伸びるとソースが見にくくてしょうがない。あと、N+M回まわりたいときはどう書くんだ?

(N+M).times
{ |i|
	sum += i;
}

ダサすぎる。普通のforのほうがマシである。ループ構造なのだから、先頭に「これはループですよ」とわかる識別子が無いと可読性が悪いだろ。

foreach i in 10
	sum += i;

まだこちらのほうがマシだ。しかし「in 10」って英語的にどうなのか。これ絶対おかしいだろ。あと、foreachの"each"とタイプするのも面倒だ。forだけにさせてくれ。

for i 10 times
	sum += i;

言わんとすることはわかるが、どう見ても片言英語だ。しかもこの文法構造だと次のように書いたとき、Xが型名なのか変数名なのかを確定させるのにtimesのところまで読みにいかないと確定しない。

for X N times
	sum += i;

違う。こんなことがしたいんじゃない。ちなみに、VC++でソースを入力することが前提なら、次のようにforの直後に"("を持ってきて、普通のfor文に見せかけてインテリセンスを騙すテクニックが考えられる。

	for(i in e)
		sum += i;

この場合、"sum += i"の部分を入力しているときに正しくインテリセンスが機能する。ここを"foreach"にしてしまうとインテリセンスは騙せない。いや、ちょっと待てよ。ダミーのforeachをdefineで定義しておけばインテリセンスを騙せるなぁ。

// ダミーのforeach
#define foreach(X)

どうせインテリセンスを騙すつもりならYaneCの文法をC#と文法をコンパチにしてしまう方法も考えられる。そうすればReSharperのような強力な開発支援ツールが使える。


しかし、C#だとtypedefやCのdefineのようなマクロが使えなくて、私の開発しているプログラムではC#の文法に準拠させるにはかなり追加コストがかかるのだ。それはとりあえずは避けたい。


やはりVC++のインテリセンスを騙せる範囲で拡張記法を考えるのがよろしい。PASCAL風に':'を導入してはどうか。

	for(i:10 times)
		sum += i;

これは読みやすいだろうか?またこの場合、多重ループは次のようになる。

	for(i:10times,j:5times,k:3..5)
		sum += i*j*k;

あとはC#のようにユーザー定義型に対してもfor(foreach)を定義できるようにしたい。しかしこのとき":"だとPASCALの型宣言のようでforeachっぽくない。

for(sq:uservar)
	target&=mask[sq];

やはり、次のように書かれているほうが私としては読みやすい。

for(sq in uservar)
	target&=mask[sq];

ここまで書いてきてから言うのも何だが、これなら、Cで普通にforeach_XXXをdefineして、次のように書けばいいんじゃないかと言う話になる。読みやすさで言えばさほど変わらない。末尾の"});"が気になるだけの話だ。

foreach_XXX(sq,uservar,{
	target&=mask[sq];
});

スタート地点に戻ってしまった。何をやっているのかさっぱりわからない。


そんなわけで、美しい回数ループの記法を求む!


・回数ループが美しく書ける
・回数ループのループ変数がわかりやすく表記できる
・読みやすいforeach構文
・多重foreachが簡潔に書ける
・インテリセンスを騙せる


以上の条件をある程度満たすものが望まれる。コメント欄でお願いします(´ω`)人