可以访问Option容器的选项操作员

时间:2014-12-05 15:16:44

标签: scala

我有一些函数(f2..fn)取一个A,然后返回选项[A]。这很好地工作(假设f1:X =>选项[A])来做例如。

f1(x) flatMap f2 flatMap f3

现在我希望能够记录发生的事情,特别是在无介绍的地方。我希望能够插入一个函数,如:

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") ...

我无法立即看到一种优雅,惯用的方法 - 我无法在&lt;。&gt;中看到任何内容。位置。

3 个答案:

答案 0 :(得分:4)

对于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进行类似的事情,但它更痛苦,因为你需要在整个地方使用.toRightProjection

我假装验证与Validation.FlatMap导入是一致的,即使它不是,但是如果您的f1,2,3不是,那么您也可以使用应用版本来收集多个错误。需要排序。 http://eed3si9n.com/learning-scalaz/Validation.html

答案 1 :(得分:2)

我认为andThen是您在这里寻找的方法,虽然它并不那么漂亮:

(f1[A] _ andThen log_none("f1 failed"))(x) flatMap (f2[A] _ andThen log_none("f2 failed")) ...

答案 2 :(得分:1)

您可以使用隐式类:

scala> implicit class LogEmptyOption[A](opt: Option[A]) {
     |   def logNone(m: String): Option[A] = {
     |     if (opt.isEmpty)
     |       println(m)
     |     opt
     |   }
     | }
defined class LogEmptyOption

scala> Option.empty[String].logNone("No Such element")

这使您可以扩展(可以说)原始类,而无需实际创建新的子类。