C2E6
いい加減な実装ですけど、関数を追加しました。ラムダ計算だと簡単に追加出来ていいです。
{val add = (a)=>(b)=>a+b; add(1)(2)}
1+2=3を計算出来ます。
{(a)=>(b)=>a+b}(1)(2)だと名前無しで実行出来る。
ひたすら手計算で環境をああしてこうしてって考えていたので、環境を保存する考えが今までよりより直感的に分かっていたのでさくっと実装出来た。
package C2E6 import util.parsing.combinator._ object parser extends RegexParsers{ def expr: Parser[E] = term~rep("+"~>term) ^^ { case a ~ b => b.foldLeft[E](a){case (a, b)=> EAdd(a,b)} } def term : Parser[E] = app~rep("*"~>app) ^^ { case a ~ b => b.foldLeft[E](a){case(a, b) => EMul(a,b)} } def app : Parser[E] = factor~rep("("~>factor<~")") ^^ { case a ~ b => b.foldLeft[E](a){case(a, b) => EApp(a,b)} } def factor: Parser[E] = intLiteral | valExpr | id | fun | "("~>expr<~")" | block | unit def fun: Parser[E] = ("("~>id<~")") ~ ("=>"~> expr) ^^ { case (EId(a)~b) => EFun(Map(),a,b) } def unit: Parser[E] = ";" ^^ { a => EUnit } def block: Parser[E] = "{" ~> rep(expr) <~ "}" ^^ { a => def c2e(l:List[E]):E = { l match { case List() => EUnit case List(a) => a case ELet(a,b,EUnit)::c => ELet(a, b, c2e(c)) case a::b => ELet(null, a, c2e(b)) } } ELet(null,EUnit,c2e(a.filter{a=>a != EUnit})) } def valExpr : Parser[E] = ("val"~>id)~("="~>expr) ^^ { case(EId(a) ~ b) => ELet(a, b, EUnit) } def intLiteral : Parser[E] = """-?[1-9][0-9]*|0""".r ^^ { a => EInt(a.toInt) } def id : Parser[EId] = """[_a-zA-Z][_a-zA-Z0-9]*""".r ^^ { a => EId(a) } def parse(str:String) = { parseAll(expr, str) match { case Success(tree,_) => tree case e => throw new Exception(""+e) } } } sealed trait E case class EInt(a:Int) extends E case class EAdd(a:E,b:E) extends E case class EMul(a:E,b:E) extends E case class ELet(a:String, b:E, c:E) extends E case class EId(a:String) extends E case class EFun(m:Map[String,E], a:String, b:E) extends E case class EApp(a:E, b:E) extends E object EUnit extends E object Main { def main(argv:Array[String]) { test(Map(),"1",EInt(1)) test(Map("a"->EInt(1)),"a", EId("a")) test(Map(),"1+2", EAdd(EInt(1),EInt(2))) test(Map(),"val a = 1", ELet("a",EInt(1),EUnit)) test(Map(),"{}", ELet(null, EUnit, EUnit)) test(Map(),"{1}",ELet(null,EUnit,EInt(1))) test(Map("a"->EInt(1)),"{a}", ELet(null,EUnit,EId("a"))) test(Map(),"{1+2}", ELet(null,EUnit,EAdd(EInt(1),EInt(2)))) test(Map(),"{val a = 1}", ELet(null,EUnit,ELet("a",EInt(1),EUnit))) test(Map(),"{{}}", ELet(null, EUnit,ELet(null, EUnit, EUnit))) test(Map(),"{1 1}",ELet(null, EUnit,ELet(null,EInt(1),EInt(1)))) test(Map(),"{1 2 3}",ELet(null, EUnit, ELet(null,EInt(1),ELet(null, EInt(2), EInt(3))))) test(Map(),"{val a = 1 a}", ELet(null,EUnit,ELet("a",EInt(1),EId("a")))) test(Map(),"{val a = 1 val b = 2}",ELet(null,EUnit, ELet("a",EInt(1),ELet("b",EInt(2),EUnit)))) test(Map(),"{{ val a = 1} val b = 2}",ELet(null,EUnit, ELet(null,ELet(null,EUnit, ELet("a",EInt(1),EUnit)),ELet("b",EInt(2),EUnit)))) test("{val a = 5 { val a = 1 {}} val b = 2 a}", EInt(5)) test(Map(),"(a)=>a", EFun(Map(),"a", EId("a"))) test(Map(),"((a)=>a)(2)", EApp(EFun(Map(), "a", EId("a")),EInt(2))) test("((a)=>a+a)(4)", EInt(8)) test("((a)=>(b)=>a+b)(4)(5)", EInt(9)) test("{val f4=((a)=>(b)=>a+b)(4) val f2=((a)=>(b)=>a+b)(2) f4(5)+f2(8)}", EInt(19)) test("{(a)=>(b)=>(c)=>a+b*c}(4)(5)(6)", EInt(34)) test("{val a = 1 val f=(b)=>a+b f(2)}", EInt(3)) test("{val a = 1 a}", EInt(1)) test("{1}", EInt(1)) } def test(env:Map[String,E],s:String,e:E) { val e2 = parser.parse(s) if (e2 != e) throw new Exception("error "+s+" expected "+e+" but found "+e2) println(s+"="+eval(env,e2)) } def test(s:String,e:E) { val e2 = parser.parse(s) println("test "+s) val e3 = eval(Map(), e2) if (e3 != e) throw new Exception("error "+s+" expected "+e+" but found "+e3) println(s+"="+e3) } def eval(env:Map[String,E], e:E):E = { println("eval "+env+" |- "+e) e match { case EInt(a) => EInt(a) case EAdd(a, b) => (eval(env,a),eval(env, b)) match { case (EInt(a1), EInt(b1)) => EInt(a1 + b1) case _ => throw new Exception("error "+e) } case EMul(a, b) => (eval(env,a),eval(env, b)) match { case (EInt(a1), EInt(b1)) => EInt(a1 * b1) case _ => throw new Exception("error "+e) } case ELet(null, b, c) => eval(env,b); eval(env,c) case ELet(a, b, c) => eval(env+(a->eval(env,b)),c) case EId(a) => env(a) case EFun(m,a,b) => EFun(env,a,b) case EApp(a, b) => (eval(env,a),eval(env, b)) match { case (EFun(m,name,body), b1:E) => eval(m+(name->b1), body) case _ => throw new Exception("error "+e) } case EUnit => EUnit } } }