我有一些函数 (f2..fn) 接受 A,并返回 Option[A]。这非常有效(假设 f1:X => Option[A])来做例如
f1(x) flatMap f2 flatMap f3
现在我希望能够记录发生的事情,尤其是在引入 None 的地方。我希望能够插入一个函数,例如:
log_none(m:String):Option[A] => Option[A]
如果遇到 None,它会产生日志记录的副作用。
似乎没有任何选项功能适用于此(在阅读例如 tonymorris.github.io/blog/posts/scalaoption-cheat-sheet/之后)
理想情况下,它看起来像这样:
f1(x) <.> log_none("f1 failed") flatMap f2 <.> log_none("f2 failed") ...
我无法立即看到一种优雅、惯用的方式来做到这一点——我看不到任何东西可以放在 <.> 位置。
最佳答案
这是 scalaz 验证的一个很好的案例。它与 Option 类似,但它不是 None,而是给你一个错误值。
之前:
def f1(x: Int): Option[Int]
def f2(x: Int): Option[Int]
def f2(x: Int): Option[Int]
for {
x1 <- f1(x)
x2 <- f2(x1)
x3 <- f3(x2)
} yield x3
您可以使用 toSuccess 隐式进行简单的转换
import scalaz.{Validation, Success, Failure}
import scalaz.Validation.FlatMap._
import scalaz.syntax.std.option._
def oldf1(x: Int): Option[Int]
def f1(x: Int): Validation[String, Int] = oldf1(x).toSuccess("f1 failed")
def f2(x: Int): Validation[String, Int]
def f2(x: Int): Validation[String, Int]
val validatedX3: Validation[String, Int] = for {
x1 <- f1(x)
x2 <- f2(x1)
x3 <- f3(x2)
} yield x3
validatedX3 match {
case Success(i) =>
Some(i)
case Failure(errStr) =>
log(errStr)
None
}
或者交替
validatedX3.leftMap(log).toOption
你可以用 scala Either 做类似的事情,但它更痛苦,因为你需要在所有地方使用 .toRightProjection
。
我假装 Validation 是 monadic 与 Validation.FlatMap
导入即使它不是,但如果你的 f1,2,3 不这样做,你也可以使用应用版本来收集多个错误需要测序。 http://eed3si9n.com/learning-scalaz/Validation.html
关于scala - 有权访问 Option 容器的 Option operators,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27319039/