エレファント・ビジュアライザー調査記録

ビジュアルプログラミングで数式の変形を表すことを考えていくブロクです。

自由モノイドのイテレーター(23)

自由モノイドプログラミング言語の作成(MonIter バージョン1.2 仕様(7))

構文要素に対応するクラス(Function クラス:関数(引数は数値の列)の呼び出し)

定義済みの関数 zipsum、tail はこのクラスの Eval メソッドで処理します。

    /// <summary>
    /// 関数(引数は数値の列)の呼び出しを表すクラス:関数名・関数の引数(数値の列)のリストで構成されます。
    /// </summary>
    internal class Function : Term
    {
        /// <summary>
        /// 関数名
        /// </summary>
        private readonly Identifier name;
        /// <summary>
        /// 関数の引数(数値の列)のリスト
        /// </summary>
        private readonly IEnumerable<Expression> list;
        public Function(Identifier name, IEnumerable<Expression> list)
        {
            this.name = name;
            this.list = list;
        }
        /// <summary>
        /// 式を評価して無限自由モノイドの値を取得します。
        /// </summary>
        /// <param name="env">引数の値が記録されています。</param>
        /// <param name="prog">構文木の全体。関数の定義をここから取得します。</param>
        /// <returns>式の値(無限自由モノイド)</returns>
        public FreeMonoid<int> Eval(Env<FreeMonoidUnion> env, Prog prog)
        {
            Definition? definition = prog.FindDefinition(name.Name);
            if (definition == null)
            {
                // 最初から定義されている関数を実行
                if( name.Name == "zipsum")
                {
                    List<FreeMonoid<int>> valuelist = list.Select(x => x.Eval(env, prog)).ToList();
                    return valuelist[0].ZipWith(valuelist[1], (x, y) => x + y);
                }
                else if (name.Name == "tail")
                {
                    List<FreeMonoid<int>> valuelist = list.Select(x => x.Eval(env, prog)).ToList();
                    return valuelist[0].Tail();
                }
                // 定義されていなかったとき
                return FreeMonoid<int>.Zero;
            }
            else
            {
                IEnumerable<string> namelist = definition.ParamList.Select(x => x.Name);
                IEnumerable<FreeMonoid<int>> valuelist = list.Select(x => x.Eval(env, prog));
                IEnumerable<FreeMonoidUnion> unionlist = valuelist.Select(x => new FreeMonoidUnion(x));
                env = env.DefineList(namelist, unionlist);
                return definition.Exp.Eval(env, prog);
            }
        }
        /// <summary>
        /// 式を MonIter のコードの文字列に変換して取得します。
        /// </summary>
        /// <returns>MonIter のコードの文字列</returns>
        public string Print()
        {
            string prms = string.Join(", ", list.Select(x => x.Print()));
            return $"${name.Print()}({prms})";
        }
        /// <summary>
        /// 式を Python のコードの文字列に変換して取得します。
        /// </summary>
        /// <param name="yieldp">yield を表示するかどうか</param>
        /// <param name="typep">型名を表示するかどうか</param>
        /// <param name="indp">インデントを表示するかどうか</param>
        /// <param name="indcount">インデントの個数</param>
        /// <param name="perf">式のステートメントの文字列を変換する関数</param>
        /// <returns>Python のコードの文字列</returns>
        public string GeneratePython(bool yieldp, bool typep, bool indp, int indcount, Func<string, string> perf)
        {
            if (yieldp)
            {
                return $"yield from {name.Print()}(" + Prog.ListGeneratePython(false, typep, false, indcount, perf, ", ", list) + ")";
            }
            else
            {
                return $"{name.Print()}(" + Prog.ListGeneratePython(false, typep, false, indcount, perf, ", ", list) + ")";
            }
        }
        /// <summary>
        /// 式を C# のコードの文字列に変換して取得します。
        /// </summary>
        /// <param name="yieldp">yield return を表示するかどうか</param>
        /// <param name="typep">型名を表示するかどうか</param>
        /// <param name="indp">インデントを表示するかどうか</param>
        /// <param name="indcount">インデントの個数</param>
        /// <param name="perf">式のステートメントの文字列を変換する関数</param>
        /// <returns>C# のコードの文字列</returns>
        public string GenerateCS(bool yieldp, bool typep, bool indp, int indcount, Func<string, string> perf)
        {
            if (yieldp)
            {
                return $"foreach (int e in {name.Print()}(" + Prog.ListGenerateCS(false, typep, false, indcount, perf, ", ", list) + $"))\r\n" + Prog.GenerateCSBlock(indcount, true, "yield return e;\r\n");
            }
            else
            {
                return $"{name.Print()}(" + Prog.ListGenerateCS(false, typep, false, indcount, perf, ", ", list) + ")";
            }
        }
    }