Введите лямбда с более высоким видом

В Дотти дано следующее:

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, 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, Model, 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, Model, Create] = f(client)
  }
}

Но компилятор жалуется:

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

Что для меня не имеет смысла. Какой правильный синтаксис, если он есть?

Ссылка на scastie с этим кодом

PS: Я не хочу вводить дополнительные параметры типа в BaseCreate. Особенно F так как это будет означать класс Domain.Create должен быть final case class Create[F[_]] что вовсе не является предполагаемым решением.

1 ответ

Решение

Думаю, вы перепутали лямбды типов с полиморфными функциями.

Лямбда типа отображает типы в типы, полиморфная функция отображает значения в значения, только тип ее аргумента может варьироваться.

Для лямбда-выражений типа вы должны использовать =>>, для полиморфных функций следует использовать обычные => (дважды т.е. [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

Кажется, это ошибка.

Другие вопросы по тегам