I have these types:
SomeTypeClass
A higher kinded type which has one type parameter of kind * => * => *
trait SomeTypeClass[P[_, _]] {
def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: P[A, B])
(implicit ev: Strong[P],
ev2: Choice[P],
ev3: Applicative[F]): P[S, T]
}
Target
which accepts three type parameters:
type constructor F[_]
and two polymorphic types A, B
case class Target[F[_], A, B](f: A => F[B])
I want to implement an instance of SomeTypeClass of Target.
I am using the kind-projector plugin in order to create a partially applied type.
My desired method signature should be:
implicit def instance: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[Target[F, *, *]],
ev2: Choice[Target[F, *, *]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
I've tried using this syntax using two star parameters:
implicit def instance[F[_]]: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[Target[F, *, *]],
ev2: Choice[Target[F, *, *]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
But the F[_]
declared at the instance level shadows the F[_]
declared at the test method (I want them to be the same F), so I've moved to the λ syntax and got two different unwanted results.
The first one using λ[(F, A, B) => Target[F, A, B]]
generated for the pab
paramter,
pab: Target[A, B, B]
instead of pab: Target[F, A, B]
and also for the return type Target[S, T, B]
instead of Target[F, S, T]
The second one using the F at the end of the triple type lambda parameters (why???)
λ[(A, B, F) => Target[F, A, B]]
generated the correct types for the pab
parameter and the return type, but
for each one of the implicit parameters the type Strong[λ[(A, B, F) => Target[F, A, B]]]
instead of
Strong[Target[F, *, *]]]
The full code:
import cats.Applicative
import cats.arrow.{Choice, Strong}
final case class Target[F[_], A, B](f: A => F[B])
trait SomeTypeClass[P[_, _]] {
def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: P[A, B])
(implicit ev: Strong[P],
ev2: Choice[P],
ev3: Applicative[F]): P[S, T]
}
object SomeTypeClass {
implicit def instance1: SomeTypeClass[λ[(F, A, B) => Target[F, A, B]]] = new SomeTypeClass[λ[(F, A, B) => Target[F, A, B]]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[A, B, B])
(implicit ev: Strong[Target],
ev2: Choice[Target],
ev3: Applicative[F]): Target[S, T, B] = ???
}
implicit def instance2: SomeTypeClass[λ[(A, B, F) => Target[F, A, B]]] = new SomeTypeClass[λ[(A, B, F) => Target[F, A, B]]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[λ[(A, B, F) => Target[F, A, B]]],
ev2: Choice[λ[(A, B, F) => Target[F, A, B]]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
}
Can I achieve the desired syntax using this plugin?
Why does the plugin generate different types
for different order of type lambda's 'parameters'?