Reputation: 15284
I have the following code:
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 is a type that takes any collection type. When I do customReduce, calling foos.flatMap
should return the same type as foos, which is CC1[Foo[CC2]]
, but the compiler resolves it to the base Iterable
and complains:
type mismatch;
found : Iterable[Int]
required: CC1[Int]
Why does this happen and how can I resolve this?
EDIT: it appears that after Iterable extends IterableOps, the CC type is fixed to Itearble. How can I make the above code work?
Upvotes: 1
Views: 105
Reputation: 15284
Here is the solution I found myself:
Since flatMap
is from IterableOps and Foo::foo
requires Iterable, I need to declare CC1 as the compound type of IterableOps
and 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))
Now flatMap correctly resolves to CC1 thanks to IterableOps.flatMap
signature that returns original CC
Upvotes: 2
Reputation: 51658
In Scala 2.13 you can use 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))
Upvotes: 2