为什么理解扩展为`withFilter`

时间:2015-05-22 16:45:32

标签: scala for-comprehension scalding

我正在研究用于关系(类似SQL)运算符的DSL。我有一个Rep[Table]类型,其中.apply: ((Symbol, ...)) => Obj方法返回一个定义Obj.flatMap: T1 => T2函数的对象.map: T1 => T3。由于类型Rep[Table]对基础表的模式一无所知,apply方法就像投影一样 - 仅投影参数元组中指定的字段(很像untyped scalding api) 。现在类型T1是一个“类似元组”,它的长度受到一些无形魔法约束到投影元组的长度,但是否则元组元素的类型由api用户决定,所以代码如

val a = loadTable(...)
val res = a(('x, 'y)).map { (t: Row2[Int, Int]) =>
  (1, t(0))
}

val res = a(('x, 'y)).map { (t: Row2[String, String]) =>
  (1, t(0))
}

工作正常。请注意,必须明确指定map / flatMap函数的参数类型。但是,当我尝试将其用于理解时

val a = loadTable(...)
val b = loadTable(...)
val c = loadTable(...)

val res = for {
  as: Row2[Int, Int] <- a(('ax, 'ay))
  bs: Row2[Int, Int] <- b(('bx, 'by))
  cs: Row2[Int, Int] <- c(('cx, 'cy))
} yield (as(0), as(1), bs(0), bs(1), cs(0), cs(1))

抱怨缺少withFilter运营商。添加.withFilter: T1 => Boolean不会削减它 - 然后它会抱怨“缺少扩展函数的参数类型”,因为T1是由某种类型参数化的。只添加.withFilter: Row[Int, Int] => Boolean使其有效,但显然不是我想要的。

我的问题是:为什么withFilter首先被调用,如何将其与我的参数化类似元组T1一起使用?

修改 最后,我使用了.withFilter: NothingLike => BoolLike这是一个noop用于简单检查,例如_.isInstanceOf[T1]和更受限制的.filter: T1 => BoolLike,以便在一般情况下使用。

2 个答案:

答案 0 :(得分:14)

不幸的是,当您期望基于lambda的参数类型进行类型推断时,您不能使用for-comprehensions。

实际上,在您的示例中,as: Row2[Int, Int]被解释为模式匹配:

val res = for {
  as: Row2[Int, Int] <- a(('ax, 'ay))
} yield (...)

转换为:

a(('ax, 'ay)).withFilter(_.isInstanceOf[Row2[Int, Int]]).map(...)

理解中的模式匹配非常有用:

val names = for {
  ("name", name) <- keyValPairs
} yield name

但权衡是,你不能明确指定lambda的参数类型。

答案 1 :(得分:2)

我也碰到了这个问题。感谢gzm0解释Scala编译器的行为,我提出了这个解决方法:

import cats._
import cats.data._
import cats.implicits._

object CatsNEL extends App {
  val nss: NonEmptyList[(Int, String)] = NonEmptyList.of((1,"a"), (2, "b"), (3, "c"))
  val ss: NonEmptyList[String] = for {
    tuple <- nss
    (n, s) = tuple
  } yield s
}