键入更高种类的 lambda
Type lambda with higher kind
在 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, 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[_]] =>> KeystoneClient[F] => CrudService[F, M, Create]
这对我来说没有意义。如果有的话,正确的语法是什么?
Link to scastie with this code
PS:我不想再给BaseCreate
引入类型参数了。特别是 F
,因为这意味着 class Domain.Create
需要 final case class Create[F[_]]
,这根本不是预期的解决方案。
我猜你搞糊涂了 type lambdas with polymorphic 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[_]]
(x: App.KeystoneClient[F]):
App.CrudService[F, App.Domain, App.Create]
}
[F[_]] => (client: KeystoneClient[F]) => client.domains
似乎是一个错误。
在 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, 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[_]] =>> KeystoneClient[F] => CrudService[F, M, Create]
这对我来说没有意义。如果有的话,正确的语法是什么?
Link to scastie with this code
PS:我不想再给BaseCreate
引入类型参数了。特别是 F
,因为这意味着 class Domain.Create
需要 final case class Create[F[_]]
,这根本不是预期的解决方案。
我猜你搞糊涂了 type lambdas with polymorphic 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[_]]
(x: App.KeystoneClient[F]):
App.CrudService[F, App.Domain, App.Create]
}
[F[_]] => (client: KeystoneClient[F]) => client.domains
似乎是一个错误。