scalatypeshigher-kinded-typestype-kindskind-projector

Why does Option[Try[_]] not conform to F[_]?


So having something like this:

@ trait IntWrapper[F[_]] { def apply(i: Int): F[Int] }
defined trait IntWrapper

@ class OptWrapper extends IntWrapper[Option] { def apply(i: Int) = Option(i) }
defined class OptWrapper

I now want to do something like this:

@ class TryOptWrapper extends IntWrapper[Try[Option]] { def apply(i: Int) = Try(Option(i)) }
cmd19.sc:1: scala.util.Try[Option] takes no type parameters, expected: one
class TryOptWrapper extends IntWrapper[Try[Option]] { def apply(i: Int) = Try(Option(i)) }
                                       ^
Compilation Failed

(Same thing if I declare the trait extension as class TryOptWrapper extends IntWrapper[Try[Option[_]]])

Now, perhaps the most interestingly, this works:

@ type Topt[T] = Try[Option[T]]

@ class ToptWrapper extends IntWrapper[Topt] { def apply(i: Int) = Try(Option(i)) }
defined class ToptWrapper

Now, is it possible to do the same thing – i.e. implement a trait with a type parameter being a nested parametrized type – without having to explicitly declare the type alias? It definitely feels like I'm missing some syntax here.


Solution

  • Try expects type parameter of kind * and Option has kind * => * so you can't write Try[Option], only Try[Option[Int]], Try[Option[String]], Try[Option[_]]...

    Try type lambda

    class TryOptWrapper extends IntWrapper[({ type λ[A] = Try[Option[A]] })#λ] { def apply(i: Int) = Try(Option(i)) }
    

    Or with kind-projector

    class TryOptWrapper extends IntWrapper[Lambda[A => Try[Option[A]]]] { def apply(i: Int) = Try(Option(i)) }