Enforcing that dependent return type must implement typeclass

后端 未结 1 1857
一整个雨季
一整个雨季 2021-01-23 10:03

I am trying to enforce a rule that the (dependent) return type of a typeclass, must itself implement a typeclass. So when the user implements the IsVec typeclass be

相关标签:
1条回答
  • 2021-01-23 10:37

    IsVecOps shouldn't extend IsVec. Implicit class (with the only purpose to introduce an extension method) extending a type class would be very strange.

    If for a moment you remove access modifier (protected) you'll see that the error message changes to

    illegal dependent method type: parameter may only be referenced in a subsequent parameter section
        def getElem...
    

    Try to add a type parameter (OE) and specify type refinement (IsVec[A, T] { ... })

    implicit class IsVecOps[A, T: Numeric](value: A) {
      def getElem[OE](i: Int)(implicit tcA: IsVec[A, T] { type OutElem = OE }, tcO: IsVecElem[OE, T]): OE = tcA.getElem(value, i)
    }
    

    If you introduce Aux-type

    object IsVec {
      type Aux[A, T, OE] = IsVec[A, T] { type OutElem = OE }
    }
    

    then you can rewrite type refinement more compactly

    implicit class IsVecOps[A, T: Numeric](value: A) {
      def getElem[OutElem](i: Int)(implicit tcA: IsVec.Aux[A, T, OutElem], tcO: IsVecElem[OutElem, T]): OutElem = tcA.getElem(value, i)
    }
    

    How can I have a method parameter with type dependent on an implicit parameter?

    When are dependent types needed in Shapeless?

    Why is the Aux technique required for type-level computations?

    Understanding the Aux pattern in Scala Type System

    In Dotty you'll be able to use trait parameters, extension methods, multiple implicit parameter lists, types of parameters in the same parameter list dependent on each other:

    trait IsVecElem[A, T: Numeric] {
      def dataOnly(self: A): T
    }
      
    trait IsVec[A, T: Numeric] {
      protected type OutElem
      def (self: A) getElem(i: Int)(using IsVecElem[OutElem, T]): OutElem
    }
    

    or

    trait IsVecElem[A, T: Numeric] {
      def dataOnly(self: A): T
    }
    
    trait IsVec[A, T: Numeric] {
      /*protected*/ type OutElem
      def getElem(self: A, i: Int)(using IsVecElem[OutElem, T]): OutElem
    }
    extension [A, T: Numeric](value: A) {
      def getElem(i: Int)(using tcA: IsVec[A, T], tcO: isVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
    }
    

    (tested in 0.28.0-bin-20200908-ce48f5a-NIGHTLY)

    0 讨论(0)
提交回复
热议问题