D言語による関数型プログラミング

関数型プログラミングでは、変数に関数を代入したり、引数や戻り値を関数にすることができます。
D言語では、function宣言された引数や戻り値には関数リテラルやグローバル関数が適用され、delegate宣言された引数や戻り値には関数リテラルやローカル関数(関数内で定義された関数)、メンバ関数(クラス内で定義された関数)が適用されます。
また、delegate宣言の場合は、適用された関数がその関数の外側の変数や関数にアクセスすることができるのに対し、function宣言の場合はそれができません。クロージャは、delegate のこの機能を利用して作成されます。

注)クロージャは、状態変数を保持した関数のようなもので、任意の値で状態変数を初期化した上で複数のクローンを生成することができます。C言語では、内部にstatic変数を保持した関数がクロージャに相当しますが、デフォルトで状態変数を初期化することしかできず、クローンを生成することもできません。

functional.d
import std.stdio;

int function(int, int) gf = (i, j) {return i + j;};
//auto gf = function(int i, int j) {return i + j;};

int gadd(int i, int j) {
  return i + j;
}

int function(int, int) fadd() {
  return &gadd;
}

/*
int function(int, int) fadd() {
  return (i, j) => i + j;
}
*/

int applyf(int function(int, int) f, int i, int j) {
  return f(i, j);
}

class Arithmetic {
  int add(int i, int j) {
    return i + j;
  }
}

void main() {
  int function(int, int) lf = (i, j) {return i + j;};
  //auto lf = function(int i, int j) {return i + j;};

  int delegate(int, int) ld = (i, j) {return i + j;};
  //auto ld = delegate(int i, int j) {return i + j;};

  int ladd(int i, int j) {
    return i + j;
  }

  int delegate(int, int) dadd() {
    return &ladd;
  }

/*
  int delegate(int, int) dadd() {
    return (i, j) => i + j;
  }
*/

  int applyd(int delegate(int, int) d, int i, int j) {
    return d(i, j);
  }

  int function(int, int) f = &gadd;
  writeln((&gadd)(1, 1));
  writeln(fadd()(1, 1));
  writeln(applyf(f, 1, 1));
  writeln(applyf(gf, 1, 1));
  writeln(applyf(lf, 1, 1));
  writeln(applyf(&gadd, 1, 1));
  writeln(applyf((i, j) => i + j, 1, 1));

  int delegate(int, int) d = &ladd;
  auto arithmetic = new Arithmetic();
  writeln((&ladd)(1, 1));
  writeln(dadd()(1, 1));
  writeln(applyd(d, 1, 1));
  writeln(applyd(ld, 1, 1));
  writeln(applyd(&ladd, 1, 1));
  writeln(applyd((i, j) => i + j, 1, 1));
  writeln(applyd(&arithmetic.add, 1, 1));
}

currying.d
import std.stdio;

auto at1 = (int i, int j) {return i + j;};
auto at2 = (int i) {return (int j) {return i + j;};};

int function(int, int) fp1 = (i, j) {return i + j;};
int delegate(int) function(int) fp2 = (i) {return (j) {return i + j;};};

int add(int i, int j) {
  return i + j;
}

int delegate(int) add(int i) {
  return (int j) {
    return i + j;
  };
}

void main() {
  writeln(at1(1, 1));
  writeln(at2(1)(1));

  writeln(fp1(1, 1));
  writeln(fp2(1)(1));

  writeln(add(1, 1));
  writeln(add(1)(1));
}

closure.d
import std.stdio;

int delegate(int, int) closure(int s) {
  int state = s;
  return (i, j) {
    return (i + j) * state++;
  };
}

/* NG
int function(int, int) closure(int s) {
  int state = s;
  return (i, j) {
    return (i + j) * state++;
  };
}
*/

void main() {
  auto clone1 = closure(0);
  auto clone2 = closure(10);
  foreach (i; 0..10) {
    foreach (j; 0..10) {
      writeln(clone1(i, j));
      writeln(clone2(i, j));
    }
  }
}

function_delegate_auto.d
int function(int, int) gf = (i, j) {return i + j;};       // -> OK
auto gfa = function(int i, int j) {return i + j;};        // -> OK

//int delegate(int, int) gd = (i, j) {return i + j;};     // -> NG
//auto gda = delegate(int i, int j) {return i + j;};      // -> NG

int add(int i, int j) {return i + j;}

void main() {
  int function(int, int) lf = (i, j) {return i + j;};     // -> OK
  auto lfa = function(int i, int j) {return i + j;};      // -> OK

  int delegate(int, int) ld = (i, j) {return i + j;};     // -> OK
  auto lda = delegate(int i, int j) {return i + j;};      // -> OK

  Object o;
  o = cast(Object)gf;
  o = cast(Object)lf;
  o = cast(Object)&add;
  o = cast(Object)((int i, int j) => i + j);
  //o = cast(Object)ld;   // -> NG

  void* p;
  p = gf;
  p = lf;
  p = cast(void*)&add;
  p = (int i, int j) => i + j;
  //p = cast(void*)ld;    // -> Deprecation
}

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中