kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

Scalaで値を返せるbreak

Scalaでbreakの応用で、ブロックからbreakするときに値を返せるようなものも実現できる。基本的な発想は同じだが、例外のコンストラクタパラメタとして、返すべき値を持たせるところと、ブロックが任意の型を取れるようにパラメタライズされていることが異なる。

class Ret[T](val value: T) extends Throwable
def ret[T](value: T) = throw new Ret[T](value)
def returnable[T](f: (T => Nothing) => T): T = {
  try {
    f(ret[T] _)
  } catch {
    case e:Ret[_] => e.asInstanceOf[Ret[T]].value
  }
}

サンプルプログラム。コマンドライン引数の数が0個なら即座にブロックから"args not found"をreturnして、1個以上ならargs(0)の値を表示する。

println(
  returnable[String]{ret =>
    if(args.length < 1) ret("args not found")
    "args(0) = " + args(0)
  }
)

ちなみに、値をreturnするための関数を明示的に渡しているのは、returnableから普通に返る値と、途中でreturnした場合の型で不整合が起きないようにするため。returnableがネストするとそれでもおかしくなるが、それを回避しようと思うとブロックにラベル付けられるようにとかしなきゃならなくなって面倒なので後は放置。