6

私が持っていると仮定します

type VS[A] = Validation[String, A]

val v: VS[Option[A]]
val f: A => VS[B]

タイプの結果を取得したいのですVS[Option[B]]が、vが a のSuccess(None)場合、結果もSuccess(None). 次に例を示します。

scala> val v: VS[Option[String]] = some("4.5").success
v: VS[Option[String]] = Success(Some(4.5))

scala> val f = (s : String) => (try { s.toInt.success } catch { case x => x.getMessage.fail }): VS[Int]
f: String => VS[Int] = <function1>

それで:

scala> import Validation.Monad._
import Validation.Monad._

scala> (v map2 f map (_.sequence)).join
res4: scalaz.Validation[String,Option[Int]] = Failure(For input string: "4.5")

成功例は次のとおりです。

scala> val v: VS[Option[String]]= some("5").success
v: VS[Option[String]] = Success(Some(5))

scala> (v map2 f map (_.sequence)).join //UGLY composition
res7: scalaz.Validation[String,Option[Int]] = Success(Some(5))

空のケースは次のとおりです。

scala> val v: VS[Option[String]]= none[String].success
v: VS[Option[String]] = Success(None)

scala> (v map2 f map (_.sequence)).join
res6: scalaz.Validation[String,Option[Int]] = Success(None)

これを行うための「より良い」方法はありますか (おそらく kleisli コンポジションまたはモナド トランスフォーマーを含む)?

4

1 に答える 1

5

モナド変換子OptionTは、ここで必要なことを正確に実行し、そのflatMapF方法により、使用法がクリーンなワンライナーになります。

\/後者はScalaz7のモナドではないため、この例の代わりにScalaz 7の論理和タイプ()を使用しますValidationが、原理は同じです。

import scalaz._, std.option._, syntax.id._, syntax.monad._

type DS[+A] = String \/ A
type ODS[A] = OptionT[DS, A]

def f(s: String) = try s.toInt.right catch { case e => e.getMessage.left }

これで、次のように書くことができます。

scala> val v = OptionT(some("4.5").point[DS])
v: scalaz.OptionT[DS,java.lang.String] = OptionT(\/-(Some(4.5)))

scala> (v flatMapF f).run
res0: DS[Option[Int]] = -\/(For input string: "4.5")

または同等に:

scala> ("4.5".point[ODS] flatMapF f).run
res1: DS[Option[Int]] = -\/(For input string: "4.5")

または成功事例:

scala> ("4".point[ODS] flatMapF f).run
res2: DS[Option[Int]] = \/-(Some(4))

または空のケース:

scala> (OptionT(none.point[DS]) flatMapF f).run
res3: DS[Option[Int]] = \/-(None)

望んだ通りに。

于 2012-09-16T14:52:02.330 に答える