输入更高种类的lambda

问题描述

Dotty 中,给出以下信息:

object Domain {
  final case class Create(name: String) extends BaseCreate[Create] {
    override type Model = Domain
    override def service[F[_]](client: KeystoneClient[F]): CrudService[F,Domain,Create] = client.domains
  }
}
case class Domain(id: String)

class CrudService[F[_],Model,Create]
final class Domains[F[_]] extends CrudService[F,Domain.Create]

class KeystoneClient[F[_]] {
  val domains = new Domains[F]
}

trait BaseCreate[Create <: BaseCreate[Create]] {                                                                                                        
  type Model
  def service[F[_]](client: KeystoneClient[F]): CrudService[F,Create]
}

我想“简化” BaseCreate,以便可以像这样实现Create

final case class Create(name: String) extends BaseCreate.Aux[Domain,Create](_.domains)

我尝试过:

object BaseCreate {
  abstract class Aux[M,Create](f: [F[_]] =>> KeystoneClient[F] => CrudService[F,M,Create]) extends BaseCreate[Create] {                                        
    type Model = M
    def service[F[_]](client: KeystoneClient[F]): CrudService[F,Create] = f(client)
  }
}

但是编译器抱怨:

Missing type parameter for [F[_$5]] =>> KeystoneClient[F] => CrudService[F,Create]

这对我没有意义。什么是正确的语法(如果有)?

Link to scastie with this code

PS:我不想在BaseCreate中引入更多类型参数。尤其是F,因为那将意味着类Domain.Create将需要为final case class Create[F[_]],而这根本不是预期的解决方案。

解决方法

我想您将type lambdaspolymorphic functions混淆了。

lambda类型将类型映射为类型,多态函数将值映射为仅其参数类型可以变化的值。

对于lambda类型,应使用=>>,对于多态函数,应使用普通的=>(两次,即[A] => (a: A) => f(a))。

所以应该是

object BaseCreate {
  abstract class Aux[M,Create](f: [F[_]] => KeystoneClient[F] => CrudService[F,M,Create]) extends BaseCreate[Create] {
    type Model = M
    def service[F[_]](client: KeystoneClient[F]): CrudService[F,Model,Create] = f(client)
  }
}
   
final case class Create(name: String) extends BaseCreate.Aux[Domain,Create](
  [F[_]] => (client: KeystoneClient[F]) => client.domains
)

但是它无法在Dotty 0.28.0-bin-20200920-e99793e-NIGHTLY中编译,但出现错误

Found:    Object with PolyFunction {...}
Required: PolyFunction{
  apply: 
    [F[_$6]]
      (x$1: App.KeystoneClient[F]): 
        App.CrudService[F,App.Domain,App.Create]
}
    [F[_]] => (client: KeystoneClient[F]) => client.domains

似乎是个错误。