Scalaz:过滤器在| @ |中扮演什么角色?

时间:2015-12-31 16:42:16

标签: scala scalaz monad-transformers

我们在Futures上使用了WriterT monad转换器希望从异步应用程序中获取更多有组织的日志,但是我们遇到了一些麻烦。

如果我编译下面的应用程序,我会收到以下错误。请注意,这不是关于withFilter的警告。

  

[error]值过滤器不是scalaz.WriterT的成员[scala.concurrent.Future,List [String],String]

为什么| @ |需要在这里过滤? Scalaz是否为此案例提供了隐式转换?

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scalaz._
import Scalaz._

object Failure extends App {

  type LoggedT[F[_], A] = WriterT[F, List[String], A]
  type LoggedFuture[A] = LoggedT[Future, A]

  //this is the applicative behavior that we want WriterT to preserve
  val example = for {
    z <- (Future("left") |@| Future("right")) { (x: String, y: String) => x + " " + y }
  } yield z

  example.onSuccess { case x => println(x) }

  val test = for {
    z: String <- (Future("left").liftM[LoggedT] |@| Future("right").liftM[LoggedT]) { (x: String, y: String) => x + " " + y }
  } yield z

  test.value.onSuccess { case x => println(x) }

}

Scala版本发生错误:2.11.7和Scalaz版本:7.2.0

1 个答案:

答案 0 :(得分:7)

使用反射库的reify通常可以很方便地查看在去除期间发生的事情(这是我唯一一次建议从中导入任何东西scala.reflect.runtime,即使在这种情况下,仅在开发期间的REPL中):

scala> import scala.reflect.runtime.universe.reify
import scala.reflect.runtime.universe.reify

scala> reify(for { x: Int <- Option(1) } yield x)
res5: reflect.runtime.universe.Expr[Option[Int]] =
Expr[scala.Option[Int]](Option.apply(1).withFilter(((check$ifrefutable$1) => check$ifrefutable$1: @unchecked match {
  case (x @ (_: Int)) => true
  case _ => false
})).map(((x: Int) => x)))

问题是 for -comprehension中的类型案例模式匹配。尽管编译器将验证匹配是否安全(例如for { x: String <- Option(1) } yield x不会编译),但它仍然不熟悉过滤操作。我不确定为什么 - 这可能是它的原因,而且这也是一个很小的机会,这是一个很好的理由。

您收到有关filter的消息,因为在这种情况下,这是编译器的最后手段。首先,它会尝试去打电话withFilter,如果它找不到withFilter,它会使用filter(至少在收藏中在这种情况下,库的实现通常效率较低。在WriterT的情况下,它既没有找到(因为过滤作者在一般情况下没有意义),所以它抱怨它尝试的最后一个。

解决方案是不使用类型大小写匹配。写一个简单的旧for { z <- ... } yield z,一切都会正常工作。实际上I'd suggest not ever using type-case matching - 它是运行时反射相关问题最终出现在代码中的最偷偷摸摸的方式。在这种情况下,将在编译时检查操作(至少在明显的情况下),但它仍然是不必要的,可能效率较低。