エレファント・コンピューティング調査報告

極限に関する順序を論理プログラミングの手法を使って指定することを目指すブロクです。

ラムダ計算と無限ラムダ多項式(9)

Calc クラスの IterateServer です。

        public static Func<string> IterateServer = () =>
            new ExpBlock {
                Exp.Define("take", new NameList{"count", "gen"},
                    Exp.If(
                        Exp.Func("==", Exp.Name("count"), Exp.Number(0)),
                        Exp.Nil(),
                        new ExpBlock
                        {
                            Exp.Let(new NameList{"next", "getCurrent", "setCurrent"}, Exp.Name("gen")),
                            Exp.If(Exp.Func("next"),
                                Exp.Cons(
                                    Exp.Func("getCurrent"),
                                    Exp.Func("take", Exp.Func("-", Exp.Name("count"), Exp.Number(1)), Exp.Name("gen"))
                                    ),
                                Exp.Nil())
                        }
                    )
                ),
                Exp.Define("zipn", new NameList{"f", "n", "list"},
                    Exp.If(
                        Exp.Func("null", Exp.Name("list")),
                        Exp.Nil(),
                        Exp.Cons(
                            Exp.Func(Exp.Name("f"), Exp.Func("first", Exp.Name("list")), Exp.Name("n")),
                            Exp.Func("zipn", Exp.Name("f"), Exp.Func("+", Exp.Name("n"), Exp.Number(1)), Exp.Func("tail", Exp.Name("list")))
                        )
                    )
                ),
                Exp.Define("nlist", new NameList{"list"},
                    Exp.Func("zipn",
                        Exp.Fun(new NameList{"n", "e"},
                            Exp.Func("*",
                                Exp.Name("n"),
                                Exp.Func("^",
                                    Exp.Number(10),
                                    Exp.Func("u-", Exp.Name("e"))
                                )
                            )
                        ),
                        Exp.Number(0),
                        Exp.Name("list"))),
                Exp.Define("foldr", new NameList{"f", "n", "list"},
                    Exp.If(
                        Exp.Func("null", Exp.Name("list")),
                        Exp.Name("n"),
                        Exp.Func(Exp.Name("f"),
                            Exp.Func("first", Exp.Name("list")),
                            Exp.Func("foldr", Exp.Name("f"), Exp.Name("n"), Exp.Func("tail", Exp.Name("list")))
                        )
                    )
                ),
                Exp.Define("number", new NameList{"list"},
                    Exp.Func("foldr", Exp.Fun(new NameList{"x", "y"}, Exp.Func("+", Exp.Name("x"), Exp.Name("y"))), Exp.Number(0), Exp.Func("nlist", Exp.Name("list")))),
                Exp.Define("unfoldl", new NameList{"next", "init"}, new ExpBlock {
                    Exp.Let("src", Exp.Name("init")),
                    Exp.Let("dst", Exp.Number(0)),
                    Exp.Define("next_", new NameList { }, new ExpBlock {
                        Exp.Subst(new NameList{ "dst", "src"}, Exp.Func("next", Exp.Name("src"))),
                        Exp.Bool(true),
                    }),
                    Exp.Define("getCurrent", new NameList { }, new ExpBlock {
                        Exp.Name("dst"),
                    }),
                    Exp.Define("setCurrent", new NameList { "val" }, new ExpBlock
                    {
                    }),
                    new ExpList { Exp.Name("next_"), Exp.Name("getCurrent"), Exp.Name("setCurrent") }
                }),
                Exp.Let("numbers", new ExpList { Exp.Number(0), Exp.Number(3), Exp.Number(0) }),
                Exp.Func("number",
                    Exp.Func("take", Exp.Name("count"), 
                        Exp.Func("unfoldl", Exp.Name("GetNextDecimalDigitAndNumbers"), Exp.Name("numbers")))
                )
            }.ExpEval(new Env("count", Exp.Number(count), "GetNextDecimalDigitAndNumbers", Exp.FuncExpExp(GetNextDecimalDigitAndNumbers))).Print();

上記の文字列版です。

        public static Func<string> IterateServer = () =>
            Exp.From("{" +
                "def take (count, gen) = " +
                    "if count == 0 then " +
                        "nil " +
                    "else { " +
                        "let (next, getCurrent, setCurrent) = gen; " +
                        "if next() then " +
                            "cons(getCurrent(), take(count - 1, gen)) " +
                        "else " +
                            "nil " +
                    "}; " +
                "def zipn (f, n, list) = " +
                    "if null(list) then " +
                        "nil " +
                    "else " +
                        "cons(f(first(list), n), zipn(f, n + 1, tail(list))); " +
                "def nlist (list) = " +
                    "zipn(fun(n, e) = n * 10^(-e), 0, list);" +
                "def foldr (f, n, list) = " +
                    "if null(list) then " +
                        "n " +
                    "else " +
                        "f(first(list), foldr(f, n, tail(list))); " +
                "def number (list) = " +
                    "foldr(fun (x, y) = x + y, 0, nlist(list)); " +
                "def unfoldl (next, init) = {" +
                    "let src = init; " +
                    "let dst = 0; " +
                    "def next_() = {" +
                        "subst (dst, src) = next(src); " +
                        "true" +
                    "};" +
                    "def getCurrent() = dst; " +
                    "def setCurrent(val) = {};" +
                    "(next_, getCurrent, setCurrent)" +
                "}; " +
                "let numbers = (0, 3, 0);" +
                "number(take(count, unfoldl(GetNextDecimalDigitAndNumbers, numbers))) " +
            "}").ExpEval(new Env("count", Exp.Number(count), "GetNextDecimalDigitAndNumbers", Exp.FuncExpExp(GetNextDecimalDigitAndNumbers))).Print();

BigNum も変換したいと思うのですがたいへんなので、変換するツールを作ろうと思います。C# のコードを読み込むツールが本に載っていたのですが、あまり詳しく書かれていなかったので自力で作ろうと思います。BigNum (とそれに必要なコード)が変換できれば良いですし、関数プログラミングについて調べることが目的なのでその方が良いのではないかと思います。