関数のメモ化

「関数のメモ化」というテクニックがあるみたい。

初めて知った。メソッドの引数と結果をキャッシュしているのかぁ。クロージャの「環境を包み込む」特徴を上手く使って、キャッシュ用変数を外部から見えなくしているところがステキ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace MemoSample
{
    class Program
    {
        // 関数をメモ化する
        private static Func<TArg, TResult> Memoization<TArg, TResult>(Func<TArg, TResult> source)
        {
            var dic = new Dictionary<TArg, TResult>();
            return x =>
            {
                if (!dic.ContainsKey(x))
                {
                    // 初めて渡される引数のときは計算
                    dic[x] = source(x);
                }
                return dic[x];
            };
        }

        private static int HeviyCalc(int n)
        {
            Thread.Sleep(1000);
            return n * n;
        }

        static void Main(string[] args)
        {
            var func = Memoization<int, int>(HeviyCalc);

            foreach (var i in Enumerable.Range(0, 5))
            {
                Console.WriteLine(func(i));
            }

            foreach (var i in Enumerable.Range(0, 5))
            {
                Console.WriteLine(func(i));
            }

            Console.ReadLine();
        }
    }
}

ジェネリックで実装してみたけど、もっと汎用的に実装できるはず。