Scala 可以访问选项容器的选项运算符

Scala 可以访问选项容器的选项运算符,scala,Scala,我有一些函数(f2..fn),它们接受A,并返回选项[A]。这非常有效(假设f1:X=>Option[A]),例如 f1(x) flatMap f2 flatMap f3 现在我想能够记录下发生了什么,尤其是在没有人介绍的情况下。我希望能够插入一个函数,例如: log_none(m:String):Option[A] => Option[A] 如果没有遇到任何问题,则会产生日志记录的副作用 所有选项功能似乎都不适用于此(在阅读了例如tonymorris.github.io/blog/

我有一些函数(f2..fn),它们接受A,并返回选项[A]。这非常有效(假设f1:X=>Option[A]),例如

f1(x) flatMap f2 flatMap f3
现在我想能够记录下发生了什么,尤其是在没有人介绍的情况下。我希望能够插入一个函数,例如:

log_none(m:String):Option[A] => Option[A] 
如果没有遇到任何问题,则会产生日志记录的副作用

所有选项功能似乎都不适用于此(在阅读了例如tonymorris.github.io/blog/posts/scalaoption备忘单之后)

理想情况下,它会看起来像:

f1(x) <.> log_none("f1 failed") flatMap f2 <.> log_none("f2 failed") ...
f1(x)log_none(“f1失败”)平面图f2 log_none(“f2失败”)。。。

我无法立即找到一种优雅、惯用的方法来做到这一点——我看不到任何东西可以放在这个位置上。

这是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
您也可以使用scala执行类似的操作,但更痛苦的是,您需要到处使用
.toRightProjection


我用
Validation.FlatMap
import假装验证是一元的,尽管它不是,但是如果您的f1,2,3不需要排序,您也可以使用应用程序版本来收集多个错误

您可以使用隐式类:

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

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

我认为,
然后,
是您在这里寻找的方法,尽管它没有那么漂亮:

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

很好的答案,我都喜欢。我认为这与我所要求的最接近,隐式类对现有代码的破坏最小,scalaz可能是最正确的方法。所以不知道该接受哪一个。我将尝试隐式类,看看结果如何。
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")
(f1[A] _ andThen log_none("f1 failed"))(x) flatMap (f2[A] _ andThen log_none("f2 failed")) ...