Scala for = Haskell do (Java の例外を Either で包んだ後の話し)
最近、こっそりと RabbitMQ Java Client の Scala Wrapper を書いています。
Scala から Java のライブラリを使う場合、例外処理の扱いに困るのですが、当然、RabbitMQ Java Client も例外投げまくりです。
そこで scala.util.control.Exception.allCatch を使って例外を包んでみました。*1
class ConnectionFactory (factory: MQFactory) { def connect(): Either[Throwable, Connection] = allCatch either { new Connection(factory.newConnection) } } object ConnectionFactory { def apply(setter: (ConnectionConfig => Unit)): Either[Throwable, ConnectionFactory] = { allCatch either { val factory = new MQFactory setter(new ConnectionConfig(factory)) new ConnectionFactory(factory) } } }
コードの詳細はさておき「ConnectionFactory クラスの connect メソッドと、ConnectionFactory オブジェクトの apply メソッドが Either を返している」というのがポイントです。
さて、ここからが本題ですが、これを match case で処理*2しようとすると…
object Connection { def apply(setter: (ConnectionConfig => Unit)): Either[Throwable, Connection] = ConnectionFactory(setter) match { case Right(factory) => factory.connect() match { case Right(connection) => Right(connection) case other => other } case other => other } }
こんな感じで match case がネストしまくりな状態に陥ります。
今回のパターンでは、ネストが二段ですが、これが三段・四段と深くなると更に難読化していきます。
そこで、実際に ConnectionFactory を使う所では、下記のようにしています。
object Connection { def apply(setter: (ConnectionConfig => Unit)): Either[Throwable, Connection] = for { factory <- ConnectionFactory(setter).right connection <- factory.connect().right } yield connection }
Scala の for は、Haskell の do 記法のように使えます。
突っ込み・添削 大歓迎。