if式オーバーロード
注意
本物のif式ではありません。
if式っぽいもの。
概要
動的型付け言語では、if式(条件式)がいろいろな型について使える。
(数値型、オブジェクト型、など)
それを静的型付けのScalaでやってみる。
実装
オーバーロードといえば型クラス。
Scalaで型クラスといえばtraitへのimplicit conversion
(+今回必要なかったけどview bound)らしい。
package myif trait Condition { def condition : Boolean } object IfTest { def If[T](a : Condition) = new If[T](a) def main(args : Array[String]) : Unit = { //Either val right = If(Right("right")) Then 100 Else 200 val left = If(Left("left")) Then 100 Else 200 //Option val some = If(Some("some")) Then 100 Else 200 val none = If(None) Then 100 Else 200 //Int val one = If(1) Then 100 Else 200 val zero = If(0) Then 100 Else 200 //Double val oned = If(1.0) Then 100 Else 200 val zerod = If(0.0) Then 100 Else 200 //mixin is OK val testObj = new Object with Condition { override def condition = true } val obj = If(testObj) Then 100 Else 200 //Boolean //only hoge is printed If(true) Then { println("hoge") } Else { println("fuga") } println(right) println(left) println(some) println(none) println(one) println(zero) println(oned) println(zerod) println(obj) //odd use val thenthen = If(true) Then 100 Then 200 println(thenthen Else 300) println(thenthen Else 400) } implicit def boolean_condition(b : Boolean) : Condition = { new Condition { override def condition = b } } implicit def option_condition[T] (x : Option[T]) : Condition = { new Condition{ override def condition = !x.isEmpty } } implicit def either_condition[T, U](x : Either[T, U]) : Condition = { new Condition{ override def condition = x.isRight } } implicit def int_condition(n : Int) : Condition = { new Condition{ override def condition = n != 0 } } implicit def double_condition(d : Double) : Condition = { new Condition{ override def condition = d != 0 } } } class If[T](cond : Condition) { var truecase : () => T = null var falsecase : () => T = null def Then(truecase : => T) : If[T] = { this.truecase = () => truecase this } def Else(falsecase : => T) : T = { this.falsecase = () => falsecase if(cond.condition){ this.truecase() } else { this.falsecase() } } }
作り方
- 条件になるオブジェクトの抽象クラス(traitにした)Conditionを用意する。
trueになるかfalseになるかを表すconditionフィールドを定義しておく。
- implicit conversionを用意。ここではBoolean, Option, Either, Int, Doubleなど。
- If式はいろいろな型を返せるので
型パラメータTをもたせたクラスIfを用意する。
- 構文がそれっぽく見えるようにThenとElseを遅延評価で実装し、
Ifをグローバルな関数にしておく。
Scalaにはthenがないがあった方がよい気がする。
try-catchと同じ要領。
http://d.hatena.ne.jp/kya-zinc/20090722/1259845362
動作
- 使われないブランチは評価されない。
- implicit conversionを使わずとも、ミックスインで
条件になるオブジェクトを増やせることを確認。(testObj)
- ThenでIfインスタンスが返ってくるので怪しい使い方ができる。(thenthen)