Is it possible to somehow provide a type bound for a higher-kinded type, something like F[A] <: G[A] for each A
? After all, the higher-kinded types allow such relations, for example: Some and Option, List and Seq.
Or is it enough in practice for this relationship to hold for some particular type, for example F[Any] <: G[Any]
, and that would implicitly mean the former?
Here is the example that puzzles me: Scastie - An interactive playground for Scala.
trait Bind[F[_]]:
extension [A](fa: F[A])
def myMap[B](f: A => B): F[B]
def myFlatMap[B](f: A => F[B]): F[B]
given Bind[Option] with
extension [A](fa: Option[A])
def myMap[B](f: A => B): Option[B] = fa.map(f)
def myFlatMap[B](f: A => Option[B]): Option[B] = fa.flatMap(f)
def tuple[F[_]: Bind, A, B](fa: F[A], fb: F[B]): F[(A, B)] =
fa.myFlatMap(a => fb.myMap((a, _)))
def tuple2[F[Any] <: G[Any], G[_]: Bind, A, B](fa: F[A], fb: F[B]): G[(A, B)] =
fa.myFlatMap(a => fb.myMap((a, _)))
tuple[Option, Int, String](Some(1), Some("aaa"))
tuple2(Some(1), Some("aaa"))
//tuple(Some(1), Some("aaa"))
Somehow, the tuple2
compiles and even produces the expected result in the case of two Some-values, whereas tuple
throws a compile error “No given instance of type Bind[Some]
was found”.
And it even does not matter which type I use: Any
, A
, B
, or anything else, really. I can even use G[Any]: Bind
and it will still work!