遅延評価

遅延評価は, 式の値が実際に必要になるまで, 式の評価 (実際の値を求めるの計算) を 後回しにする技術である.

lazy_eval.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import std.stdio;

void dotimes(uint count, lazy void dg){
/*
  引数に lazy を使うとその引数は遅延評価されるようになる
  writeln("hello") の評価を dg() の呼び出しまで遅らせている
*/
  for(uint i = 0; i < count; i++){
    dg();
    // dg; // この使い方も OK
  }
}

void main(){
  dotimes( 5, writeln("hello") );
}

lazy_eval.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./lazy_eval
hello
hello
hello
hello
hello

lazy_eval2.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import std.stdio;
import std.perf;

// 普通の関数
void normal(string s, int i){
  if (i % 1000000 == 0)
    write(s);
}

// 引数を遅延評価する関数
void lazyEval(lazy string s, int i){
  if(i % 1000000 == 0)
    write(s);
}

// 実際に必要になるまで遅延評価される関数
string text(){
  char[] ret;
  for(int i = 0; i < 10; i++)
    ret ~= "A";
  ret.length = 0;
  return ret.idup;
}

void main(){
  auto t1 = new std.perf.PerformanceCounter;
  auto t2 = new std.perf.PerformanceCounter;

  // 普通の関数
  t1.start();
  for(int i = 0; i < 50000000; i++)
    normal(text(), i);
  t1.stop();
  writeln("normal: ", t1.milliseconds, "[ms]");

  // 引数を遅延評価する関数
  t2.start();
  for(int i = 0; i < 50000000; i++)
    lazyEval(text(), i);
  t2.stop();
  writeln("lazy: ", t2.milliseconds, "[ms]");
}

lazy_eval2.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./lazy_eval2
normal: 67344[ms]
lazy: 356[ms]

tak_norm_lazy.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import std.stdio;
import std.perf;

// 普通の竹内関数
int normTak(int x, int y, int z){
  if(x <= y)
    return y;
  else
    return normTak( normTak(x-1, y, z), normTak(y-1, z, x), normTak(z-1, x, y) );
}

// 引数を遅延評価する竹内関数
int lazyTak(lazy int x, lazy int y, lazy int z){
  if(x <= y)
    return y;
  else
    return lazyTak( lazyTak(x-1, y, z), lazyTak(y-1, z, x), lazyTak(z-1, x, y) );
}

void main(){
  auto t1 = new std.perf.PerformanceCounter;
  auto t2 = new std.perf.PerformanceCounter;

  // 普通の竹内関数
  t1.start();
  writeln( normTak(15, 10, 0) );
  t1.stop();
  writeln("Normal Tak Function: ", t1.milliseconds, "[ms]");

  // 引数を遅延評価する竹内関数
  t2.start();
  writeln( lazyTak(200, 50, 20) );
  t2.stop();
  writeln("Lazy Tak Function: ", t2.milliseconds, "[ms]");
}

tak_norm_lazy.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./tak_norm_lazy
15
Normal Tak Function: 48374[ms]
200
Lazy Tak Function: 39[ms]

Previous topic

契約による設計 (DbC)

Next topic

スコープガイド