D 2.011

Phobos に色々とおもしろい物が追加されたようなので少し紹介しておきます。

std.algorithm が強力になったよ

データ構造をいじくり回すための便利な関数テンプレートがたくさんできました。これは本当に便利だと思います。
とりあえずコードを見るのが一番早い。こんなような物が動きます。

import std.stdio, std.algorithm;
void main(){
  int[] a = [1,2,3,4,5];
  inPlace!(writefln)(filter!("a>4")(map!("a*a")(a)));
}
9
16
25

メソッドチェインできないのが個人的には少し残念ですが、とても気持ち悪…素晴らしいですね。
勿論もう少し素直に書くこともできます。

  inPlace!("if(a*a>4) writefln(a*a)")(a);

…というかわけの分からない文字列なんて渡してやらなくても、Dには無名関数があるじゃない…と思った人はその通りで、下のようにも書けます。

  inPlace!((int a){if(a*a>4)writefln(a*a);})(a);

他にも関数っぽいものならなんでも指定できます。ファンクタとか。
文字列とか気持ち悪いよ、と思うかも知れませんが、引数宣言をしなくていいのでタイプ量が少な、alias しておいていろんな型に使いまわしたりできます。無名関数を使う方法ではできないことです。
他にも min や max、count、findIf や…色々あるんですが、適当にまとめるとまあ大体あります!
一つ一つ紹介してもいいんですが、面倒なのでkinabaさん頑張ってくださいということで…!(えー)

std.algorithm の実装 (というか std.functional.(u|bi)naryFun の解説)

さてあのわけの分からない文字列は一体何なのかというと、まあここ見てるような人なら大体分かるかとは思いますが mixin を使って定義した関数を利用して操作しているわけです。
その関数を定義するための関数テンプレートテンプレート(なんのことやら)が存在して、それが std.functional.unaryFun と std.functional.binaryFun です。

import std.stdio, std.functional;
void main(){
  writefln(unaryFun!("a*a")(2,));
  writefln(binaryFun!("a*b")(2, 2));
}
4
4

こんな風に関数を生成する事ができます。すごいですね。
まあmixin使って関数生成は誰でも考えた事があるはずなので(?)すぐに分かると思うんですが、困るのは返値型です。

  assert( is( typeof( binaryFun!("a*b")(2,2) ) == int) );      // ?
  assert( is( typeof( binaryFun!("a*b")(2,3.4) ) == double) ); // ?

typeof(mixin( ... )) で動いちゃうのかなーと思ってソース除いたら、こんなことになってました。

template binaryFun(string comp) {
    // @@@BUG1816@@@: typeof(mixin(comp)) should work
    typeof({ ElementType1 a; ElementType2 b; return mixin(comp);}())
    binaryFun(ElementType1, ElementType2)(ElementType1 a, ElementType2 b)
    {
        return mixin(comp);
    }
}

返値を決定するときに既に引数が定義されていれば typeof(mixin(comp)) でも通るが定義されていないため、先に解決されている関数テンプレートのテンプレート引数型を見て、その型の(勿論引数と同じ名前の)変数をローカルに持つ無名関数を作って、その無名関数の返値をチェックしている、と…。
しかし should work って…まあ確かに、mixin と typeof が存在する以上は動くべき気もする。
渡される静的文字列と引数の型に依存して関数の返値が決まるっていうのはおもしろいなーと思います。勿論どちらもコンパイル時には分かる情報なので何も問題はないんですが、それができる言語はなかなか無いんじゃないですか多分。ボクは他に知りません。

std.iterator が増えたよ

std.algorithm の関数テンプレートの中に、Iteratorとか返す物がありますね。
まあなんというかそのまんまイテレータです。軽く説明すると、

  • イテレータの実装は配列の場合ただのポインタです。イテレータクラスのオブジェクトとかじゃないです。
  • algorithmで逆順に辿りたかったらRetroっていうの使ってね。
  • Retroのイテレータは普通に構造体です。バグバグなので使わないでね。

といった感じです。ほんとに軽い説明だな。
Retroとポインタとでインターフェイスが違うので、ちょっとどうなの、と思います。もう完全にポインタと同等のことできるようにすれば…とボクは思うんですが。
まあRetroは怪しいのでもう少し様子見でいい気がします。具体的にはforeachができなかったり++が怪しかったりします。なんでvoid返すの?


これからお仕事なので続きは気が向いたら書きますが、多分世界樹の迷宮IIやるので書かないと思います。
追記:やっぱり書きませんでした。さらにいうと編集押そうとしてスター押しました。悔しい!