通过将类型参数与参数的路径相关类型匹配来约束操作 [英] Constraining an operation by matching a type parameter to an argument's path-dependent type

查看:148
本文介绍了通过将类型参数与参数的路径相关类型匹配来约束操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想利用Scala的类型系统来限制系统中的操作,在该系统中存在对某些值的版本化引用.这一切都发生在某些事务上下文Ctx中,该事务上下文附加了版本类型V.现在有一个Factory可以创建参考变量.创建它们时会附带一个 creation 版本(类型参数V1),该版本与调用工厂的上下文版本相对应.

I would like to exploit Scala's type system to constrain operations in a system where there are versioned references to some values. This is all happening in some transactional context Ctx which has a version type V attached to it. Now there is a Factory to create reference variables. They get created with a creation version attached them (type parameter V1), corresponding to the version of the context in which the factory was called.

现在想象一下,有些代码尝试使用后来的版本访问该引用,即使用不同的Ctx.我要实现的是,禁止在与创建版本不匹配的任何版本(CtxV type字段)中调用该Ref上的访问权限,但允许您解析该访问权限.通过某种替代机制进行引用,该机制将返回Ref的新视图,该视图可以在当前版本中进行访问. (如果用无效的上下文调用substitute是可以的,例如,早于RefV1的上下文-在这种情况下,可能会抛出运行时异常)

Now imagine that some code tries to access that reference in a later version, that is using a different Ctx. What I want to achieve is that it is prohibited to call access on that Ref in any version (Ctx's V type field) that doesn't match the creation version, but that you are allowed to resolve the reference by some substitution mechanism that returns a new view of the Ref which can be accessed in the current version. (it's ok if substitute is called with an invalid context, e.g. one that is older than the Ref's V1 -- in that case a runtime exception could be thrown)

这是我的尝试:

trait Version

trait Ctx {
  type V <: Version
}

object Ref {
  implicit def access[C <: Ctx, R, T](r: R)(implicit c: C, view: R => Ref[C#V, T]): T =
    view(r).access(c)

  implicit def substitute[C <: Ctx, T](r: Ref[_ <: Version, T])
                                      (implicit c: C): Ref[C#V, T] = r.substitute(c)
}
trait Ref[V1 <: Version, T] {
  def access(implicit c: { type V = V1 }): T // ???
  def substitute[C <: Ctx](implicit c: C): Ref[C#V, T]
}

trait Factory {
  def makeRef[C <: Ctx, T](init: T)(implicit c: C): Ref[C#V, T]
}

问题是,以一种整体编译的方式定义类方法access,即应该编译复合对象的access,但同时我不能使用<来调用该类方法access. em> any Ctx,只能使用其版本与参考版本相匹配的版本.

And the problem is to define class method access in a way that the whole thing compiles, i.e. the compound object's access should compile, but at the same time that I cannot call this class method access with any Ctx, only with one whose version matches the reference's version.

最好不要使用结构化类型或任何会影响性能的内容.

Preferably without structural typing or anything that imposes performance issues.

推荐答案

仅供参考,以下是我喜欢的另一个想法,因为客户端代码相当整洁:

FYI, and to close the question, here is another idea that I like because the client code is fairly clutter free:

trait System[A <: Access[_]] {
  def in[T](v: Version)(fun: A => T): T
}

trait Access[Repr] {
  def version: Version
  def meld[R[_]](v: Version)(fun: Repr => Ref[_, R]): R[this.type]
}

trait Version

trait Ref[A, Repr[_]] {
  def sub[B](b: B): Repr[B]
}

object MyRef {
  def apply[A <: MyAccess](implicit a: A): MyRef[A] = new Impl[A](a)

  private class Impl[A](a: A) extends MyRef[A] {
    def sub[B](b: B) = new Impl[B](b)
    def schnuppi(implicit ev: A <:< MyAccess) = a.gagaism
  }
}
trait MyRef[A] extends Ref[A, MyRef] {
  // this is how we get MyAccess specific functionality
  // in here without getting trapped in more type parameters
  // in all the traits
  def schnuppi(implicit ev: A <:< MyAccess): Int
}

trait MyAccess extends Access[MyAccess] {
  var head: MyRef[this.type]
  var tail: MyRef[this.type]
  def gagaism: Int
}

def test(sys: System[MyAccess], v0: Version, v1: Version): Unit = {
  val v2 = sys.in(v0) { a => a.tail = a.meld(v1)(_.head); a.version }
  val a3 = sys.in(v2) { a => a }
  val (v4, a4) = sys.in(v1) { a =>
    a.head = a.head
    println(a.head.schnuppi) // yes!
    (a.version, a)
  }
  // a3.head = a4.head // forbidden
}

这篇关于通过将类型参数与参数的路径相关类型匹配来约束操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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