このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

併置をオーバーロードするという極悪非道

J言語が難読である要因は色々ありますが、演算子が激しくオーバーロードされていることも理由のひとつです。さらには、演算子記号を省略した併置(juxtaposition)がオーバーロードされていることは、プログラム(式)の解釈を相当に困難にしています。あまりにヒドイので、かえって笑っちゃいますよ。

併置とは、構文上は単に並べることです。日常的にお馴染みの例は掛け算です。a×x + b は、掛け算演算子記号「×」を省略して、ax + b と書いてもいいですよね。このとき、aとxの併置は掛け算演算子の省略と解釈します。別な言い方をすると、併置演算子が掛け算演算子の別記法として使われているのです。

プログラミング言語において併置がどんな意味を持つかは、たいていは天下りに決まっています。例外的に、CafeOBJ(マイナーな言語)では、併置演算もユーザー定義できます。「雑談しながら思ったこと」という記事のjmkさんのコメントによると、「juxtaposition operatorはFortressで使えます。」とのこと。Fortressもあまり一般化しなかったマイナー言語ですけど。

さて、J言語の場合ですが、併置の意味は言語仕様で決まっています。例えば、1次元配列(リスト)の平均値を求める例(有名らしい)は次のようになります。


average =: + / % #
average 5 8 7 5 11
7.2

ユーザー定義演算子averageは、「+」「/」「%」「#」という4つの記号の併置で構成されます。上の定義では、分かりやすいように空白をはさんで併置してますが、「+」「/」「%」「#」は演算子記号であり、それ自体で区切りとなるので、+/%# とくっつけて書いても同じです。名前を付ける必要も特にないので、次のようにインラインでいきなり書いてもOKです。


(+/%#)5 8 7 5 11
7.2

J言語は、「右から左に読み、演算子の優先順はない」と「J言語の印象: その変態さと可能性」で言いました。であるなら、+ / % # は、

  • (+ (/ (% #)))

と解釈されそうです。残念ながら違います。「/」は普通の演算子より偉いメタ演算子なので、結合力が強いのです。しかも引数を左側からとります(普通の単項演算子は右側に引数)。+ / の部分を優先すると、

  • ((+ /) (% #))

でしょうか? これも違います。


((+ /) (% #))5 8 7 5 11
6 6.6 6.4 6 7.2
9 9.6 9.4 9 10.2
8 8.6 8.4 8 9.2
6 6.6 6.4 6 7.2
12 12.6 12.4 12 13.2

演算子が複数並ぶとき、(f g) と (f g h) は特別な解釈をします。4つ以上並ぶときは、右からグループ化して解釈します。とにかくヤヤコシイのですが、+ / % # に関して言えば、「+/」「%」「#」を3つの引数とするメタ演算子(「フォーク」と呼ぶ)が併置として(つまり単に3つ並べることで)表現されています。

ちなみに、(+/%#)5 8 7 5 11 の括弧をはずして、+/%#5 8 7 5 11 とすると、まったく違った意味になります。


+/%#5 8 7 5 11
0.2

x, y はリテラル値、f, g, h が演算子(J言語の動詞)のとき、併置は次のような複数の解釈を持ちます。

  1. (x y) は、配列を作る。
  2. (f y) は、値yに、単項演算子fを適用。
  3. (x g y) は、値xとyに、二項演算子gを適用。
  4. (f g) は2つの演算子のフック(説明略)を作る。
  5. (f g h) は3つの演算子のフォーク(説明略)を作る。

極悪非道な文法ですな。