暗黙の型変換を考える(2)
とりあえず、インタプリタ的に考えるとScalaだと以下のように書けました。
object testt { def main(argv:Array[String]) { var prg = (1,"+",2.2) var rc = t(prg) println(rc) } def t(p:Any):Any = p match { case (a,"+",b) => ic(a,b,{case (a:Int,b) => (a,"+",b) case (a:Double, b) => (a,"+.", b) }) } def toDouble(t:Any):Double = t match { case t:Int => t case t:Double => t } def toInt(t:Any):Int = t match { case t:Int => t } def ic(a:Any, b:Any, f:(Any,Any)=>Any):Any = (a,b) match { case (a:Double, b) => f(a, toDouble(b)) case (a, b:Double) => f(toDouble(a), b) case (a:Int, b) => f(a, toInt(b)) case (a, b:Int) => f(toInt(a), b) } }
toDouble, toIntはキャストしたいのだけど、Scalaの場合はIntはJavaのIntegerでDoubleにキャストは出来ないので、関数をかませる事でウマく動きました。
それで、double同士の演算はdouble同士で計算とすることで動きました。
次に、キャスト演算子を付けるだけの物を考えてみます。
object testt { def main(argv:Array[String]) { var prg = ((("Int",1),"+",("Double",2.2)),"*",("Int", 3)) var rc = t(prg) println(rc) } def t(p:Any):Any = p match { case (a,"+",b) => ic(t(a),t(b),{case (a, b, c) => (a,("Add",b,c)) }) case (a,"*",b) => ic(t(a),t(b),{case (a, b, c) => (a,("Mul",b,c)) }) case a => a } def ic(a:Any, b:Any, f:(Any,Any,Any)=>Any):Any = (a,b) match { case (("Double", a), ("Double", b)) => f("Double", a, b) case (("Double", a), b) => f("Double", a, ("Double", ("castDouble",b))) case (a, ("Double", b)) => f("Double", ("Double", ("castDouble", a)), b) case (("Int",a), ("Int",b)) => f("Int", a, b) case (("Int",a), b) => f("Int", a, ("Int", ("castInt", b))) case (a, ("Int", b)) => f("Int", ("Int", ("castInt", a)), b) } }
と言う感じに書けました。
型を付けると
object testt { trait TType case class TDbl(a:Exp) extends TType case class TInt(a:Exp) extends TType case class TNone(a:Exp) extends TType trait Exp case class Add(a:TType,b:TType) extends Exp case class Mul(a:TType,b:TType) extends Exp case class CastInt(a:TType) extends Exp case class CastDbl(a:TType) extends Exp case class EInt(a:Int) extends Exp case class EDbl(a:Double) extends Exp def main(argv:Array[String]) { var prg = TNone(Mul(TNone(Add(TInt(EInt(1)),TDbl(EDbl(2.2)))),TInt(EInt(3)))) var rc = t(prg) println(rc) } def t(p:TType):TType = p match { case TNone(Add(a, b)) => ic(t(a),t(b),(b, c) => Add(b,c)) case TNone(Mul(a, b)) => ic(t(a),t(b),(b, c) => Mul(b,c)) case a => a } def ic(a:TType, b:TType, f:(TType,TType)=>Exp):TType = (a,b) match { case (a@TDbl(_), b@TDbl(_)) => TDbl(f(a, b)) case (a@TDbl(_), b) => TDbl(f(a, TDbl(CastDbl(b)))) case (a, b@TDbl(_)) => TDbl(f(TDbl(CastDbl(a)), b)) case (a@TInt(_), b@TInt(_)) => TInt(f(a, b)) case (a@TInt(_), b) => TInt(f(a, TInt(CastInt(b)))) case (a, b@TInt(_)) => TInt(f(TInt(CastInt(a)), b)) } }
のように書けたのでした。
型から型に変換していって、Castが必要ならCastを入れるって形になったんですけど、いいのか悪いのかよくわかりません。