SwiftMango
SwiftMango

Reputation: 15284

Higher kinded type's flatMap return type is resolved to base Iterable instead of the higher kinded type itself

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

Answers (2)

SwiftMango
SwiftMango

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

Dmytro Mitin
Dmytro Mitin

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

Related Questions