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