C# で以下のような式を書くことができるようにします。
Exp.Number ( 数値 )
数値を表します。「数値」は整数、文字列、または BigNum です。
Exp.Bool ( 真理値 )
真理値を表します。
Exp.String ( 文字列 )
文字列を表します。
Exp.Name ( 文字列 )
変数名などの名前、または演算子を表します。
Exp.Func ( 関数名, 引数リスト ) または Exp.Func ( 関数名, 引数, 引数, … , 引数 )
関数を実行します。関数名は名前または関数を表す式です。
Exp.Let ( 変数名, 式 )
変数に式の値を代入します。
Exp.Subst ( 変数名, 式 )
すでに存在する変数に式の値を代入します。
Exp.If ( 式(条件), 式(真のとき), 式(偽のとき) )
「式(条件)」が真のとき「式(真のとき)」、「式(偽のとき)」が評価されます。
Exp.Define ( 関数名, 変数名リスト, 式 )
関数を定義します。
Exp.From ( 文字列 )
式を表す文字列で式を作ります。
new ExpBlock { 式, 式, … , 式 }
式を順の実行します。
new ExpList { 式, 式, … , 式 }
式のリストを表します。
new NameList { 式, 式, … , 式 }
名前のリストを表します。
ExpBlock、ExpList、NameList は以下のようなクラスを継承したものです。こうすると上記のような書き方ができます。
internal class GenList<T> : IEnumerable<T> { private List<T> list; public GenList() { list = new List<T>(); } public IEnumerator<T> GetEnumerator() { return list.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Add(T x) { list.Add(x); } public IEnumerable<(T, U)> Zip<U>(GenList<U> list2) { for (int i = 0; i < list.Count && i < list2.list.Count; i++) { yield return (list[i], list2.list[i]); } } }
例
足し算
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("123.456")), Exp.Let("y", Exp.Number("12.34")), Exp.Let("z", Exp.Func("+", Exp.Name("x"), Exp.Name("y"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: 135.796
引き算
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("123.456")), Exp.Let("y", Exp.Number("12.34")), Exp.Let("z", Exp.Func("-", Exp.Name("x"), Exp.Name("y"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: 111.116
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("123.456")), Exp.Let("y", Exp.Number("12.34")), Exp.Let("z", Exp.Func("-", Exp.Name("y"), Exp.Name("x"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: -111.116
掛け算
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("123.456")), Exp.Let("y", Exp.Number("12.34")), Exp.Let("z", Exp.Func("*", Exp.Name("x"), Exp.Name("y"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: 1523.44704
整数の割り算の商
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("1234")), Exp.Let("y", Exp.Number("12")), Exp.Let("z", Exp.Func("/", Exp.Name("x"), Exp.Name("y"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: 102
整数の割り算の余り
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("1234")), Exp.Let("y", Exp.Number("12")), Exp.Let("z", Exp.Func("%", Exp.Name("x"), Exp.Name("y"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: 10
整数の整数乗
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("12")), Exp.Let("y", Exp.Number("3")), Exp.Let("z", Exp.Func("^", Exp.Name("x"), Exp.Name("y"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: 1728
10 の整数乗
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("10")), Exp.Let("y", Exp.Number("3")), Exp.Let("z", Exp.Func("^", Exp.Name("x"), Exp.Name("y"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: 1000
public static Func<string> Test = () => new ExpBlock { Exp.Let("x", Exp.Number("10")), Exp.Let("y", Exp.Number("-3")), Exp.Let("z", Exp.Func("^", Exp.Name("x"), Exp.Name("y"))), Exp.Name("z") }.ExpEval(new Env()).Print();
結果: 0.001