...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

std.functional - dmd2.015

えーと

  1. 関数テンプレートの戻り値型推論ができるようになったので
  2. 前に取り組んでいたstd.bindを簡単に直せるようになってないかなと思って
  3. そのすぐ後にそういえばずっと前にstd.functionalってのが増えてたなと思い出して
  4. 早速中身を見てみたら
  5. std.bindもういらねーじゃん

となった.


ここをベースにサンプルコードを書いてお勉強.

import std.functional : unaryFun, binaryFun, adjoin, compose, pipe;
import std.typecons : Tuple;
import std.conv : to;
import std.algorithm : map;
import std.string : split;

void main()
{
    //
    // 文字列から1引数の関数を作る
    //
    alias unaryFun!("(a & 1) == 0") isEven;
    bool x = isEven(1);
    bool y = isEven(2);
    assert(x == false && y == true);
    
    //
    // 文字列から2引数の関数を作る
    //
    alias binaryFun!("a < b") less;
    bool t = less(1, 2);
    bool u = less(2, 1);
    assert(t == true && u == false);
    // 引数を文字列で渡すこともできるみたい
    alias binaryFun!("a > b") greater;
    bool v = greater("1", "2"); 
    bool w = greater("2", "1");
    assert(v == false && w == true);
    
    //
    // 関数を並列に結合
    //
    static bool f1(int a) { return a != 0; }
    static int f2(int a) { return a / 2; }
    Tuple!(bool,int) z = adjoin!(f1, f2)(5);
    // 結果はTupleになってる
    assert(z._0 == true && z._1 == 2);
    
    //
    // 関数合成1(直列に連結)
    //
    // ただしstd.functionalの306行を次のように書き換えないと動かなかった(dmd2.015にて)
    // auto doIt(E)(E a)//typeof({ E a; return fun0(fun1(a)); }()) doIt(E)(E a)
    int[] a = compose!(map!(to!(int)), split)("1 2 3");
    assert(a == [1,2,3]);
    
    //
    // 関数合成2(関数合成1の逆順に関数が呼ばれる)
    //
    int[] b = pipe!(split, map!(to!(int)))("4 5 6");
    assert(b == [4,5,6]);
}

コード中に書いているように,std.functionalの306行を

typeof({ E a; return fun0(fun1(a)); }()) doIt(E)(E a)

から

auto doIt(E)(E a)

に書き換えないとstd.functional.composeが動かないので注意.
件の戻り値型が大いに役だった.

追記

あ,関数合成はできるけど引数にリテラルをbindできないのかこれ?
じゃあbindいらなくないじゃん・・・.