【问题标题】:Why is the type information lost when calling collect on this higher-kinded type?为什么在这种更高种类的类型上调用 collect 时会丢失类型信息?
【发布时间】:2021-01-18 07:11:24
【问题描述】:

我正在尝试熟悉 Scala 中的高级类型,因此我尝试实现这个简单的方法,该方法采用 Option 的可遍历并将其展平,就像通常展平它一样。但是,编译器会引发错误,因为函数返回类型 Traversable[Any] 而不是 T[S]。为什么会这样,我怎样才能让它正常工作?

def flatten[S, T[_] <: Traversable[_]](list: T[Option[S]]): T[S] = {
  list.collect({ case Some(s) => s })
}

我想可能是我错误地定义了T 的类型,但我也尝试了T[_]: TraversableT[X] &lt;: Traversable[X],但这些都不起作用。

当然,这是可行的:

def flatten[S](list: Traversable[Option[S]]): Traversable[S] = {
  list.collect({ case Some(s) => s })
}

但我不想丢失返回类型的输入类型信息(调用flatten(List[Option[T]]) 应该返回List[T]

【问题讨论】:

  • scala 版本应该是 2.12 吗?
  • 编写操作任何类型集合的通用操作有点困难,我更喜欢使用typeclass 方法。
  • @AndreyTyukin 我在 2.11.2。如果它在不同版本中的工作方式不同,我肯定会很感激描述如何的答案。
  • 我认为 Andrey Tyukin 的意思是 Traversable 不在 2.13 中

标签: scala function collections higher-kinded-types


【解决方案1】:

这是因为collect 不返回T,它只返回Traversable。 trait Traversable 不知道继承它的任何类的类型。

此外,您的高级类型是错误的,应该是 T[x] &lt;: Traversable[x] 以避免与存在主义的怪异。你可以这样做:

def flatten[S, T[x] <: Traversable[x]](list: T[Option[S]])(
  implicit ev: collection.generic.CanBuildFrom[Traversable[Option[S]], S, T[S]]
): T[S] = list.collect { case Some(s) => s }

,或者 Luis Miguel Mejía Suárez 关于使用类型类的建议可能会更好。如果可能,我还建议使用 Scala 2.13。

trait Flatten[F[_]] {
  def flatten[S](list: F[Option[S]]): F[S]
}
object Flatten {
  def flatten[S, F[_]](list: List[Option[S]])(implicit f: Flatten[F]) = f.flatten(list)
  
  implicit val flattenList = new Flatten[List] {
    def flatten[S](list: List[Option[S]]) = list.collect { case Some(s) => s }
  }
}

【讨论】:

  • 我明白了——我感觉它可能需要CanBuildFrom,但我就是想不通语法。谢谢!
猜你喜欢
  • 1970-01-01
  • 2015-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-08
  • 1970-01-01
相关资源
最近更新 更多