3

我有这些类型: 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])

我想实现 Target 的 SomeTypeClass 的一个实例。
我正在使用 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]

第二个在三重类型 lambda 参数末尾使用 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] = ???
    }
  }

我可以使用这个插件实现所需的语法吗?
为什么插件会为 lambda 类型的“参数”的不同顺序生成不同的类型?

4

1 回答 1

2

如果我明白

但是F[_]在实例级别F[_]声明的会影响在测试方法中声明的(我希望它们相同F

正确地,您希望您的实例SomeTypeClass[Target[...]]修复F[_]. 但这对于这种类型签名test根本不可能。test一旦你有(例如)

val inst = implicitly[SomeTypeClass[Target[...]]

你可以打电话

val res1 = inst.test[List, ...]
val res2 = inst.test[Option, ...]

类型 lambdas 不提供解决此问题的方法。您需要将F[_]参数移动到SomeTypeClass或实施

implicit def instance[F[_]]: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
  override def test[G[_], S, T, A, B](f: (A => G[B]) => S => G[T])
                                     (pab: Target[F, A, B])
                                     (implicit ev: Strong[Target[F, *, *]],
                                      ev2: Choice[Target[F, *, *]],
                                      ev3: Applicative[G]): Target[G, S, T] = ???
}

我认为这是不可能的,因为你不能传递pab.ff.

编辑:类型wander

class (Choice p, Strong p) => Traversing p where
  traverse' :: Traversable f => p a b -> p (f a) (f b)
  traverse' = wander traverse

  wander :: (forall f. Applicative f => (a -> f b) -> s -> f t) -> p a b -> p s t
  wander f pab = dimap (\s -> Baz $ \afb -> f afb s) sold (traverse' pab)

是Scala 不直接支持的rank-2 类型;相反,您需要引入一个助手(它不能只是一个类型别名,因为它是 inControl.Lens.Type

trait Traversal[S, T, A, B] {
  def apply[F[_]: Applicative](f: A => F[B]): S => F[T]
}

然后

trait Traversing[P[_, _]] extends Strong[P] with Choice[P] {
  def wander[S, T, A, B](t: Traversal[S, T, A, B], pab: P[A, B]): P[S, T]
}

implicit def instance[F[_]: Applicative]: Traversing[Target[F, *, *]] = new Traversing[Target[F, *, *]] {
  def wander[S, T, A, B](t: Traversal[S, T, A, B], pab: Target[F, A, B]): Target[F, S, T] = Target(t(pab.f))
  // define Strong and Choice methods too
}

应该管用。(虽然我不确定这是猫的处理方式StrongChoice要求。)

于 2019-12-12T10:29:55.950 回答