Pythonでは0 < i < 10みたいに、数式っぽい形で数値の比較を行うことができる。これを、Scalaで(無理やり)エミュレートしてみた。汎用的に作ろうと思えば、もっと汎用的に作れるけどめんどいので、とりあえずInt型のみ対応。実装を見ればわかるけど、数式の構文木を作ってそれをevalしているようなものなので、(たぶん)かなり遅い。implicit conversionを使って、Boolean型が要求された時点で、比較演算の構文木をevalしてBoolean型を返すようにしているのがミソ。
object Op extends Enumeration { val LT = Value("<") val GT = Value(">") val LTE = Value("≦") val GTE = Value("≧") val AND = Value("∧") } import Op._ abstract class Exp case class BinOp(kind: Op.Value, lhs: Exp, rhs: Exp) extends Exp { def <(rhs: Int) = BinOp(AND, this, BinOp(LT, this.rhs, IntExp(rhs))) def >(rhs: Int) = BinOp(AND, this, BinOp(GT, this.rhs, IntExp(rhs))) def ≦(rhs: Int) = BinOp(AND, this, BinOp(LTE, this.rhs, IntExp(rhs))) def ≧(rhs: Int) = BinOp(AND, this, BinOp(GTE, this.rhs, IntExp(rhs))) } case class IntExp(value: Int) extends Exp class RichInt(val lhs: Int) { def <(rhs: Int) = BinOp(LT, IntExp(lhs), IntExp(rhs)) def >(rhs: Int) = BinOp(GT, IntExp(lhs), IntExp(rhs)) def ≦(rhs: Int) = BinOp(LTE, IntExp(lhs), IntExp(rhs)) def ≧(rhs: Int) = BinOp(GTE, IntExp(lhs), IntExp(rhs)) } implicit def toRichInt(x: Int): RichInt = new RichInt(x) implicit def BinOp2Boolean(x: BinOp): Boolean = x match { case BinOp(LT, lhs:IntExp, rhs:IntExp) => lhs.value < rhs.value case BinOp(GT, lhs:IntExp, rhs:IntExp) => lhs.value > rhs.value case BinOp(LTE, lhs:IntExp, rhs:IntExp) => lhs.value <= rhs.value case BinOp(GTE, lhs:IntExp, rhs:IntExp) => lhs.value >= rhs.value case BinOp(AND, lhs:BinOp, rhs:BinOp) => BinOp2Boolean(lhs) && BinOp2Boolean(rhs) }
使い方は以下のような感じ。
val i = 9 if(0 < i < 10) { println("0 < i < 10") } else { println("i ≦ 0 || i ≧ 10") }
実行結果。
0 < i < 10