【问题标题】:Higher kinded type's flatMap return type is resolved to base Iterable instead of the higher kinded type itself高级类型的 flatMap 返回类型被解析为基 Iterable 而不是高级类型本身
【发布时间】:2020-08-05 09:07:32
【问题描述】:

我有以下代码:

  case class Foo[+CC[A] <: Iterable[A]](foo: CC[Int])
  
  def customReduce[CC1[A] <: Iterable[A], CC2[A] <: Iterable[A]](foos: CC1[Foo[CC2]]): Foo[CC1] =
    Foo(foos.flatMap(_.foo))
  
  println(customReduce(Seq(Foo(Seq(1)))))

Foo 是一种可以接受任何集合类型的类型。当我执行 customReduce 时,调用 foos.flatMap 应该返回与 foos 相同的类型,即 CC1[Foo[CC2]],但编译器将其解析为基 Iterable 并抱怨:

type mismatch;
 found   : Iterable[Int]
 required: CC1[Int]

为什么会发生这种情况,我该如何解决?


编辑:似乎在 Iterable 扩展了 IterableOps 之后,CC 类型固定为 Itearble。我怎样才能使上面的代码工作?

【问题讨论】:

  • 您真的需要支持任何集合类型吗?编写适用于任何集合的代码是一种痛苦,并且在 2.13+2.12- 中是不同的(因此您可能希望在问题中包含您的 Scala 版本) i> - 我只会使用具体类型或使用更好的抽象,例如来自 catsMonad

标签: scala higher-kinded-types


【解决方案1】:

在 Scala 2.13 中,您可以使用 scala.collection.Factory

def customReduce[CC1[A] <: Iterable[A], CC2[A] <: Iterable[A]](foos: CC1[Foo[CC2]])(implicit 
  factory: Factory[Int, CC1[Int]]
): Foo[CC1] = Foo(foos.flatMap(_.foo).to(factory))


println(customReduce(Seq(Foo(Seq(1))))) // Foo(List(1))

【讨论】:

  • 尽管我找到了原始问题的答案,但仍选择此作为正确答案。顺便说一句,这需要创建一个额外的集合。
【解决方案2】:

这是我自己找到的解决方案:

由于flatMap来自IterableOps,而Foo::foo需要Iterable,我需要将CC1声明为IterableOpsIterable的复合类型:

def customReduce[CC1[A] <: Iterable[A] with IterableOps[A, CC1, CC1[A]], CC2[A] <: Iterable[A]](foos: CC1[Foo[CC2]]): Foo[CC1] =
    Foo(foos.flatMap(_.foo))

现在 flatMap 可以正确解析为 CC1,这要归功于返回原始 CC 的 IterableOps.flatMap 签名

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 2019-03-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 2013-09-15
    • 1970-01-01
    相关资源
    最近更新 更多