scala - 通过将类型参数与参数的路径相关类型进行匹配来约束操作

标签 scala type-parameter type-constraints path-dependent-type

我想利用 Scala 的类型系统来限制对某些值有版本引用的系统中的操作。这一切都发生在某些事务上下文中 Ctx具有版本类型 V附在它上面。现在有一个 Factory创建引用变量。它们通过附加的创建版本创建(类型参数 V1 ),对应于调用工厂的上下文版本。

现在想象一些代码试图在更高版本中访问该引用,即使用不同的 Ctx .我想要实现的是,禁止在该 Ref 上调用访问权限。在与创建版本不匹配的任何版本( CtxV 类型字段)中,但允许您通过某种替换机制解析引用,该机制返回 Ref 的新 View 可以在当前版本中访问。 (如果 substitute 被一个无效的上下文调用是可以的,例如比 RefV1 更旧的上下文——在这种情况下可能会抛出运行时异常)

这是我的尝试:

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与任何 Ctx ,只有一个版本与引用版本匹配。

最好没有结构类型或任何会带来性能问题的东西。

最佳答案

仅供引用,为了结束这个问题,这是我喜欢的另一个想法,因为客户端代码相当整洁:

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
}

关于scala - 通过将类型参数与参数的路径相关类型进行匹配来约束操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5524595/

相关文章:

c# - 如何创建一个继承自另一个类并在 CodeDom 中传递类型参数的类?

interface - 在 Haxe 中,当子类中未在 "abstract"父类(super class)中定义方法时,如何强制执行子类中的方法声明?

c# - 用作类型参数约束的空接口(interface)或空基类

scala - 有没有办法在 bool ZIO 测试中添加描述性断言消息

scala - Scala 中的不可变数据结构

javascript - 等效于 JavaScript 中的 Scala View

scala - Scala 中的默认类型参数

scala - 如何使用类型参数的Scala边界访问方法

scala - `extends` 允许调用特征中的父类(super class)型方法,但不允许自身类型

haskell - 类型约束最终变得模棱两可