Action<T>を使い倒してみる(つづき)

・・・ということでさっそく作ってみた。nが増えるにつれ素晴らしいモノが出力される。念のためにx100をコンパイルしてみてtestと表示できることを確認済み。

using System;

namespace garu.ActionN
{
    static class ActionN
    {
        const int TAB = 2;
        const string TYPE0 = "string";
        const string VALUE0 = "\"test\"";
        const string VALUE1 = "Console.WriteLine";

        static string Type(int n)
        {
            if (n == 0) return TYPE0;
            return "Action<" + Type(n - 1) + ">";
        }

        static string Tab(int p)
        {
            return new string(' ', p * TAB);
        }

        static string Value(int n, int p)
        {
            if (n == 0) return VALUE0;
            if (n == 1) return VALUE1;
            string pn = string.Format("p{0}", p + 1);
            return
                "delegate(" + Type(n - 1) + " " + pn + ")\n" +
                Tab(p) + "{\n" +
                Tab(p + 1) + pn + "(" + Value(n - 2, p + 1) + ");\n" +
                Tab(p) + "}";
        }

        static void Main(string[] args)
        {
            for (int n = 1; n < 20; n++)
            {
                string xn = string.Format("x{0}", n);
                Console.WriteLine(
                    Type(n) + " " + xn + " =\n" +
                    Value(n, 0) + ";\n" +
                    xn + "(" + Value(n - 1, 0) + ");");
            }
        }
    }
}

雑に書いた仕様書も置いとく。

メインルーチン
(+で始まるところをタイプルーチンで置き換え)
(-で始まるところを値ルーチンで置き換え)
 +[n] xn =
 -[n];
 xn(-[n-1]);

タイプルーチン
 n=0のとき
  string
 n>0のとき
  Action<+[n-1]>

値ルーチン
 n=0のとき
  "test"
 n=1のとき
  Console.Write
 n>1のとき
 (p?は値ルーチンの再帰深度で番号を増やす)
 (@は値ルーチンの再帰深度でタブを入れる)
  delegate(+[n-1] p?)
  @{
  @@p?(-[n-2]);
  @}