7

考虑以下类型定义:

trait LiftF[F[_], G[_]] {
  def liftF[A](fa: F[A]): G[A]
}

当在上下文边界中提供这种类型的隐式要求时(使用 kind 投影仪插件),我们必须这样写:

def func[A, G[_], F[_]: LiftF[?[_], G]](a: F[A]): G[A]

我想去掉这?[_]部分,所以我最初的猜测是写一个To[G[_]]返回的类型,LiftF[?[_], G]以便将上面的函数定义转换为

def func[A, G[_], F[_]: LiftF.To[G]](a: F[A]): G[A]

但是,当将类型To定义写为

type To[G[_]] = LiftF[?[_], G]

我收到以下编译错误:

Error:(17, 20) type Λ$ takes type parameters
type To[G[_]] = LiftF[?[_], G]

尝试用存在类型重写它会产生以下类型定义:

type To[G[_]] = LiftF[F, G] forSome { type F[X] }

这编译得很好,但不出所料,不能应用于其他类型参数,因此无法实现所需的函数定义。

我设法用受 aux 模式启发的代码实现了“部分应用程序”部分:

trait To[G[_]] {
  type From[F[_]] = LiftF[F, G]
}

可悲的是,这给我留下了可以说比原始语法更糟糕的语法:

def func[A, G[_], F[_]: LiftF.To[G]#From](a: F[A]): G[A]

我的问题是 - 我可以在实物投影仪的帮助下在 Scala 中实现最初提出的语法,还是应该坚持使用?[_]

4

1 回答 1

7

据我了解,kind-projector 在这里无法真正帮助您:

type To[G[_]] = LiftF[?[_], G]

只会被机械地重写成类似的东西

type To[G[_]] = ({ type T[F[_]] = LiftF[F, G] })#T

但它在 2.12.x 中是无效的,因为它需要*在定义的右侧有一个简单的 kind 类型。

如果将参数F移到左侧,则最终得到

type To[G[_], F[_]] = LiftF[F, G]

然后你必须使用 as To[G, ?[_]],这显然也不会给你买任何东西,它只是交换参数的顺序。因此,我建议您只需使用LiftF[?[_], G]并从您不必({ type L[F[_]] = LiftF[F, G] })#L明确写出的事实中获得安慰。


顺便说一句,在 Dotty 中,这很好用:

trait LiftF[F[_], G[_]] {
  def liftF[A](fa: F[A]): G[A]
}

type To[G[_]] = [F[_]] => LiftF[F, G]
def f[A, G[_], F[_]: To[G]](a: F[A]): G[A] = implicitly[LiftF[F, G]].liftF(a)
于 2019-03-21T13:34:57.567 回答