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

后端 未结 2 1729
遇见更好的自我
遇见更好的自我 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:43

    The following seems to work:

    trait Version
    
    trait Ctx[+V1 <: Version] {
      type V = V1
    }
    
    type AnyCtx   = Ctx[_ <: Version]
    type AnyRf[T] = Ref[_ <: Version, T]
    
    object Ref {
      implicit def access[C <: AnyCtx, R, T](r: R)(
        implicit c: C, view: R => Ref[C#V, T]): T = view(r).access(c)
    
      implicit def substitute[C <: AnyCtx, T](r: AnyRf[T])(implicit c: C): Ref[C#V, T] =
        r.substitute( c )
    }
    trait Ref[V1 <: Version, T] {
      def access(implicit c: Ctx[V1]): T
      def substitute[C <: AnyCtx](implicit c: C): Ref[C#V, T]
    }
    
    trait Factory {
      def makeVar[C <: AnyCtx, T](init: T)(implicit c: C): Ref[C#V, T]
    }
    
    // def shouldCompile1(r: AnyRf[String])(implicit c: AnyCtx): String = r
    
    def shouldCompile2(r: AnyRf[String])(implicit c: AnyCtx): String = {
      val r1 = Ref.substitute(r)
      r1.access(c)
    }
    
    // def shouldFail(r: AnyRf[String])(implicit c: AnyCtx): String = r.access(c)
    

    So the follow-up questions are

    1. why I need a redundancy of the type parameter for Ctx to achieve this. I hate that these type parameters accumulate like rabbits in my code.
    2. why shouldCompile1 doesn't compile —can i get the implicits to work as planned?

    EDIT:

    This is wrong, too. The variance annotation is wrong. Because now the following compiles although it shouldn't:

    def versionStep(c: AnyCtx): AnyCtx = c // no importa
    
    def shouldFail3[C <: AnyCtx](f: Factory, c: C): String = {
      val r    = f.makeVar("Hallo")(c)
      val c2   = versionStep(c)
      r.access(c2)
    }
    

提交回复
热议问题