Возвращаемый тип flatMap более высокого родства разрешается как базовый Iterable, а не как сам тип более высокого родства - PullRequest
1 голос
/ 05 августа 2020

У меня есть следующий код:

  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]

Почему это происходит и как я могу это решить?

EDIT: похоже, что после того, как Iterable расширяет IterableOps, тип CC фиксируется на Itearble. Как я могу заставить вышеуказанный код работать?

Ответы [ 2 ]

2 голосов
/ 05 августа 2020

Вот решение, которое я нашел сам:

Поскольку flatMap из IterableOps, а Foo::foo требует Iterable, мне нужно объявить CC1 как составной тип IterableOps и Iterable:

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 благодаря сигнатуре IterableOps.flatMap, которая возвращает исходный CC

2 голосов
/ 05 августа 2020

В 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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...