У меня есть следующие типы: SomeTypeClass
Тип более высокого порядка, который имеет один параметр типа вида * => * => *
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
, который принимает три параметра типа:
конструктор типа F[_]
и два полиморфных типа A, B
case class Target[F[_], A, B](f: A => F[B])
Я хочу реализовать экземпляр SomeTypeClass of Target.
Я использую подключаемый модуль kind-projector для создания частично применяемого типа.
Моя желаемая сигнатура метода должна быть:
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] = ???
}
Я пытался использовать этот синтаксис, используя два параметра звезды:
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] = ???
}
Но F[_]
, объявленный на уровне экземпляра, затеняет F[_]
, объявленный в тестовом методе (я хочу, чтобы они были одинаковыми F), поэтому я перешел к синтаксису λ и получил два разных нежелательных результата.
Первый, использующий λ[(F, A, B) => Target[F, A, B]]
, сгенерированный для параметра pab
, pab: Target[A, B, B]
вместо pab: Target[F, A, B]
, а также для возвращаемого типа Target[S, T, B]
вместо Target[F, S, T]
Второй с использованием F в конце лямбда-параметров тройного типа (почему???)λ[(A, B, F) => Target[F, A, B]]
сгенерировал правильные типы для параметра pab
и возвращаемого типа, но для каждого из неявных параметров тип Strong[λ[(A, B, F) => Target[F, A, B]]]
вместо Strong[Target[F, *, *]]]
Полный код:
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] = ???
}
}
Могу ли я достичь желаемого синтаксиса с помощью этого подключаемого модуля?
Почему подключаемый модуль генерирует разные типы для разного порядка "параметров" лямбда-типа?
λ
, генерирующего правильные типы для параметра. Ни один из них не компилируется, и я бы не ожидал. Если вы хотите использовать лямбда-тип в контекстеSomeClass[...]
, вам обязательно понадобится тип с двумя параметрами*
. - person Travis Brown   schedule 12.12.2019λ[(F, A, B) => Target[F, A, B]]
принимает три параметра, поэтому вы определенно не сможете использовать его в любом контексте, где ожидаетсяP[_, _]
. Если ваш окончательный блок кода вообще компилируется, это ошибка. - person Travis Brown   schedule 12.12.2019