美しいループ記法求む!
いま私は速度的に特化したプログラムを書かなくてはいけない。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が簡潔に書ける
・インテリセンスを騙せる
以上の条件をある程度満たすものが望まれる。コメント欄でお願いします(´ω`)人