自由モノイドプログラミング言語の作成(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) + ")"; } } }