I am trying to get familiar with higher-kinded types in Scala and so I tried implementing this simple method that takes a traversable of Option
and flattens it just like flattening it normally would. However, the compiler is raising an error because the function returns type Traversable[Any]
instead of T[S]
. Why is this, and how can I make it work correctly?
def flatten[S, T[_] <: Traversable[_]](list: T[Option[S]]): T[S] = {
list.collect({ case Some(s) => s })
}
I think that maybe I'm defining the type of T
incorrectly, but I also tried T[_]: Traversable
and T[X] <: Traversable[X]
and those didn't work either.
Of course, this works:
def flatten[S](list: Traversable[Option[S]]): Traversable[S] = {
list.collect({ case Some(s) => s })
}
But I don't want to lose the input type information on the return type (calling flatten(List[Option[T]])
should return List[T]
.
This is because
collect
doesn't return aT
, it returns only aTraversable
. The traitTraversable
doesn't know the type of whatever class is inheriting it.Furthermore, your higher-kinded type is wrong, it should be
T[x] <: Traversable[x]
to avoid weirdness with existentials. You could do something like this:, or you might be better off with Luis Miguel Mejía Suárez's suggestion of using typeclasses. I would also suggest using Scala 2.13 if possible.