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

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

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

Calc クラスの IterateGenerator と RepeatServer です。

        public static Func<string> IterateGenerator = () =>
            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.Func("number", 
                    Exp.Func("take", Exp.Name("count"), Exp.Func("GenerateDecimal"))
                )
            }.ExpEval(new Env("count", Exp.Number(count), "GenerateDecimal", Exp.FuncExp(GenerateDecimal))).Print();

        public static Func<string> RepeatServer = () =>
            new ExpBlock {
                Exp.Let("numbers", new ExpList { Exp.Number(0), Exp.Number(3), Exp.Number(0) }),
                Exp.Define("repeat", new NameList{"number","e","count" },
                    Exp.If(Exp.From("e < count"), new ExpBlock{
                        Exp.Let(new NameList{"dd", "ns"}, Exp.Func("GetNextDecimalDigitAndNumbers", Exp.Name("numbers"))),
                        Exp.Subst("numbers", Exp.Name("ns")),
                        Exp.Func("repeat",
                            Exp.Func("+",
                                Exp.Name("number"),
                                Exp.Func("*",
                                    Exp.Name("dd"),
                                    Exp.Func("^", Exp.Number(10), Exp.Func("u-", Exp.Name("e")))
                                    )
                                ),
                            Exp.Func("+", Exp.Name("e"), Exp.Number(1)),
                            Exp.Name("count")),
                        },
                        Exp.Name("number"))
                ),
                Exp.Func("repeat", new ExpList{Exp.Number(0), Exp.Number(0) , Exp.Name("count") })
            }.ExpEval(new Env("count", Exp.Number(count), "GetNextDecimalDigitAndNumbers", Exp.FuncExpExp(GetNextDecimalDigitAndNumbers))).Print();

上記の文字列版です。

        public static Func<string> IterateGenerator = () =>
            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)); " +
                "number(take(count, GenerateDecimal())) " +
            "}").ExpEval(new Env("count", Exp.Number(count), "GenerateDecimal", Exp.FuncExp(GenerateDecimal))).Print();
        public static Func<string> RepeatServer = () =>
            Exp.From("{" +
                "let numbers = (0, 3, 0);" +
                "def repeat(number, e, count) = " +
                "if e < count then { " +
                    "let (dd, ns) = GetNextDecimalDigitAndNumbers(numbers);" +
                    "subst numbers = ns;" +
                    "repeat(number + dd * 10^(-e), e + 1, count) " +
                "} else " +
                    "number;" +
                "repeat(0, 0, count)" +
            "}").ExpEval(new Env("count", Exp.Number(count), "GetNextDecimalDigitAndNumbers", Exp.FuncExpExp(GetNextDecimalDigitAndNumbers))).Print();

無名関数の構文を追加しました。

Exp.Fun ( new NameList { 変数名, 変数名, … , 変数名 }, 式 )

無名関数を表します。