Constraining an operation by matching a type parameter to an argument's path-dependent type

后端 未结 2 1745
遇见更好的自我
遇见更好的自我 2021-01-05 14:04

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 transacti

2条回答
  •  醉酒成梦
    2021-01-05 14:21

    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
    }
    

提交回复
热议问题