謎's キッチン

謎のひとりごと。Amazon欲しい物リストはこちら: https://www.amazon.co.jp/hz/wishlist/ls/CCPOV7C6JTD2

結合の優先順位の低い「.」が欲しい(ってよりもパイプ演算子)

D言語では現在、配列に対して「arr.func」を「func(arr)」に書き換えるという仕組みがある。
配列以外にも拡大する予定があるらしい。大歓迎だ。
ってことで「TypeTuple!(10, 20).add」と書けるようになるはずだ。
もしタプル構文ができれば「(10, 20).add」のように書けるようになるだろう。(実際は「,」が被ってるので「@」あたりが妥当だろう)
ただこの場合、ただでさえ括弧が押しにくいのに「add(10, 20)」に比べ一文字多くなるのであまり使われないであろう。
そこで優先順位の低い「.」を作れば良い。仮に「|」とし(実際は被ってるので「#」あたりが妥当だろう)て「10, 20 | add」とできれば煩わしい括弧を消すことができる。
「.」は対象物に何かをするという意味合いを持ってるが、「|」にはパイプという意味を持たせる事にする。xが関数の場合は「10 | x(...)」を「x(10, ...)」と等価にする。ただし、xが変数の場合は「.」と違い「10 | x」を「x=10」と等価にする(逆にC++チックに「変数(...)」を「変数=...」と等価にするのはどうか。先にopPipeやopPipe_r、opCallに引っかかる訳でややこしくなるのは確かだけど…)。そして「opPipe」と「opPipe_r」として演算子オーバーロードを追加するとしよう。

import std.stdarg, std.conv;
class Stream{
  ...
  void opPipe_r(...){
    this.writefln(_arguments, _argptr);
  }
  void opPipe(ref ...){//この書き方D言語でサポートされてなかったはず。readfではどうなってたっけ。
    this.readf(_arguments, _argptr);
  }
}
class CStream:Stream{
  ...
}
CStream dout = new CStream(1);
CStream din = new CStream(3);

とすれば、

int x, y;
din | x, ",", y;//"10,20"と入力したらx=10,y=20となる。
"x,y: ", x, ",", y | dout;//そして"x,y: 10,20"と出力される。
din | split(":") | join(",") | dout;//:を,に置換。(無駄に時間のかかる方法なのは突っ込まないこと)
(din, ":" | split), ","| join | dout;//書き方によっては読みにくくなる。このように中間で分岐する場合だ。

とできる。そう、C++のストリーム演算子が自然に実装できるのだ。
#命名規則的問題はD言語なので考えない方向で(ぉぃ
なので是非とも実装してほしいなぁと思う。以上。



#単に従来とデータの流れ方向が違うだけだよな(従来->内から外、新->左から右)。
#唯一違う所としては従来でいうところの外側の関数の引数(や変数/タプルの型)からの推論がある所(opCall_rにあたるもの)。
#opCall_rは関数のオーバーロードと相性が悪いから難しい所。
#従来: 3(2(1(0()))) 新: 0 | 1 | 2 | 3 従来(=) 0=(1=(2=3)) 従来(.) 0.1.2.3
#従来: 4(2(0,1),3) 新: (0, 1 | 2), 3 | 4 従来(=) (0,1=2),3=4 従来(.) *1;
#
#上記のを「=」を使って表した例(D言語ではfunc = valはfunc(val)になる)
#int x,y;
#x, ",", y=din;
#dout = "x,y: ", x, ",", y;
#dout = (join = (split = din, ":"), ",");
#//dout = join(",") = split(":") = din;//func(arg2) = arg1がfunc(arg1, arg2)となるなら
#//dout = join = split = din, ":", ",";//オーバーロード無し、可変個引数無し、dinは一回までだったらこれでも処理できるんだけど。前置。

*1:0,1).2,3).4 #従来: var = 2(1(0())) 新: 0 | 1 | 2 | var (var(x)を実装した場合は二つ上と同様) #従来: 3(var = 1(0())) 新: 0 | 1 | var | 3 (var(x)を実装した場合は二つ上と同様) # #従来の記法(+タプル構文)でdoutにopCall、dinにopCall_rを追加した場合の例。 #int x,y; #(x, ",", y)(din) #dout("x,y: ", x, ",", y); #dout(join(split(din, ":"), ","