Reputation: 1007
I am trying to define a case class that is parameterized with a container type (higher kind). This container type can be anything as long as it has a map method defined.
I would like to achieve this result suggested by the following code:
import scala.language.higherKinds
case class Test[A, C[A]](init: A, trans: Map[A,C[A]]) {
def convert[B](conv: A => B): Test[B, C[B]] = {
val _init = conv(init)
val _trans = trans map {case (k,v) => (conv(k) -> (v map {x => conv(x)})}
Test(_init, _trans)
}
}
the problem lies in the v map {x => conv(x)}
part of the code. Since no bound was defined for C[A]
it, obviously, does not compile.
The thing is that this container type can be an Id
(Scalaz style, but with map
instead of |>
), and Option
, or a collection (Seq
, Set
, List
, etc.)
Is there any way to tell the scala compiler that the container type will must have the map
method?
Upvotes: 0
Views: 362
Reputation: 22840
The best way to achieve what you want is by using the Functor type class.
For example here is an example using Cats.
(You could do the same using Scalaz).
import scala.language.higherKinds
import cats.Functor
import cats.syntax.functor.toFunctorOps
final case class Test[A, C[_]](init: A, trans: Map[A,C[A]])(implicit CFunctor: Functor[C]) {
def convert[B](conv: A => B): Test[B, C] = {
val _init = conv(init)
val _trans = trans map { case (k,v) => conv(k) -> v.map(x => conv(x)) }
Test(_init, _trans)
}
}
However, if for some reason you can't or don't want to use Cats/Scalaz, you could try Structural Types.
import scala.language.higherKinds
import scala.language.reflectiveCalls
final case class Test[A, C[A] <: { def map[B](f: A => B): C[B]}](init: A, trans: Map[A,C[A]]){
def convert[B](conv: A => B): Test[B, C] = {
val _init = conv(init)
val _trans = trans map { case (k,v) => conv(k) -> v.map(x => conv(x)) }
Test(_init, _trans)
}
}
Nevertheless, note that the last one will work for Option
, but will fail for List
, simple because the map
method in List receives an implicit CanBuildFrom
, and for that reason it isn't equals to the one you want.
Upvotes: 3