可以解决类型类证据参数和具体实例参数之间的类型冲突吗? [英] Can a type conflict between typeclass evidence parameter and concrete instance parameter be resolved?

查看:34
本文介绍了可以解决类型类证据参数和具体实例参数之间的类型冲突吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法保证 Scala 中的类型类存在 case 类复制方法?,我在这个新问题出现的地方提出了一个相关的问题.不幸的是,由于不明原因,我需要类型参数.

In Is there a way to guarantee case class copy methods exist with type classes in Scala?, I had a related question posed where this new problem came up. Unfortunately, for obscure reasons, I need type parameters.

我的类型类和隐式操作类看起来像:

My typeclass and implicit ops class look like:

  trait Job[J] {
    def id(jb: J): JobId
    def cmd(jb: J): String
    type M <: JobMetaData
    type JRef = J
    def meta(jb: J): M
    def pickler: Pickler[J]
    def rw: RW[J]
    def instance(jb: J, id: JobId, cmd: String, meta: M): J
  }
  object Job{

    type Aux[J0, M0] = Job[J0] {type M = M0}
    implicit class JobDispatch[J](val job: J)(implicit val ev: Job[J]) {
      def id: JobId = ev.id(job)
      def cmd: String = ev.cmd(job)
      def meta: ev.M = ev.meta(job)
      def rw: RW[J] = ev.rw
      def copyJob(
        idIn: JobId = job.id,
        cmdIn: String = job.cmd,
        metaIn: ev.M = job.meta
      ): J = ev.instance(job, idIn, cmdIn, metaIn)
    }

}

值得注意的是 instancecopyJob 方法;copyJob 旨在成为公共 API.

Of note are the instance and copyJob methods; copyJob is meant to be the public API.

现在举一个具体的例子,我有:

Now for a concrete example, I have:

  final case class OneShot(id: JobId, cmd: String, meta: SysJobMetaData) {
    type M = SysJobMetaData
  }

  object OneShot{
    implicit val rw: RW[OneShot] = macroRW
    implicit val jobOneShot: Job.Aux[OneShot, SysJobMetaData] = new Job[OneShot] {
      def id(jb: OneShot): JobId = jb.id
      def cmd(jb: OneShot): String = jb.cmd
      override type M = SysJobMetaData
      def meta(jb: OneShot): M = jb.meta
      val pickler: Pickler[OneShot] = generatePickler
      val rw: RW[OneShot] = OneShot.rw
      def instance(jb: OneShot, id: JobId, cmd: String, meta: M): OneShot =
        jb.copy(id, cmd, meta)
    }

但这给出了错误:

[error] /home/brandon/workspace/CCRS/model/src/main/scala/org/xsede/jobrunner/model/ModelApi.scala:277: type mismatch;
[error]  found   : _1.ev.M where val _1: org.xsede.jobrunner.model.ModelApi.Job.JobDispatch[J]
[error]  required: JobDispatch.this.ev.M
[error]         metaIn: ev.M = job.meta
[error]                            ^

首先,我不认为我完全理解错误.job.meta 似乎应该解析为 ev.M 类型.这能解决吗?

First, I don't think I exactly understand the error. It seems to be that job.meta should resolve to type ev.M. Can this be resolved?

编辑 1

如果我在 copyJob 定义(= ev.instance(job, idIn, cmdIn, metaIn.asInstanceOf[ev.M])),事情在本地看起来更愉快,但类型信息丢失了;M <: JobMetaData,但不出所料,原始类可能没有恢复,包括出现在扩展 JobMetaData 的类中的成员,如下面的 shell:

If I add an asInstanceOf call to make things happy locally in the copyJob definition (= ev.instance(job, idIn, cmdIn, metaIn.asInstanceOf[ev.M])), things look happier locally but type information is lost; M <: JobMetaData, but the original class is perhaps unsurprisingly not recovered, including members showing up in classes extending JobMetaData, like shell below:

value shell is not a member of _1.ev.M
[error]     val resultMaybe: Try[CommandResult] = cmd.meta.shell match {
[error]                                                    ^

推荐答案

我可能在这里遗漏了一些东西,因为有很多事情要做,但看起来隐式转换 JobDispatch 是递归的称自己.你为什么不这样做呢?直接调用meta,而不是job.meta.

I may be missing something here, cause there is quite a lot going on, but it looks like the implicit conversion JobDispatch is recursively calling itself. Why don't you do it like this? Calling meta directly, instead of job.meta.

  trait Job[J] {
    def id(jb: J): JobId
    def cmd(jb: J): String
    type M <: JobMetaData
    type JRef = J
    def meta(jb: J): M
    def pickler: Pickler[J]
    def rw: RW[J]
    def instance(jb: J, id: JobId, cmd: String, meta: M): J
  }
  object Job{

    type Aux[J0, M0] = Job[J0] {type M = M0}
    implicit class JobDispatch[J](val job: J)(implicit val ev: Job[J]) {
      def id: JobId = ev.id(job)
      def cmd: String = ev.cmd(job)
      def meta: ev.M = ev.meta(job)
      def rw: RW[J] = ev.rw
      def copyJob(
        idIn: JobId = id,
        cmdIn: String = cmd,
        metaIn: ev.M = meta
      ): J = ev.instance(job, idIn, cmdIn, metaIn)
    }
  }

这篇关于可以解决类型类证据参数和具体实例参数之间的类型冲突吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆