暗黙の型変換を考える(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を入れるって形になったんですけど、いいのか悪いのかよくわかりません。