简体   繁体   中英

Typeclass instance inheritance in Scala

I am translating the Haskell code in https://sebfisch.github.io/haskell-regexp/regexp-play.pdf in Scala for self study. I translated "class Semiring" (page 2) in this way:

  trait Semiring[S] {
    def zero: S
    def one: S
    def add(a: S, b: S): S
    def mult(a: S, b: S): S
  } 

and the related class SemiringI (page 7) in this way:

  trait SemiringI[S] extends Semiring[S] {
    def index: Int => S
  }

I had then to provide instances for specific type parameters, so I tried to proceed in what I think is the canonical way, ie, defining them as implicit vals.

  implicit val semiringLeftmost = new Semiring[LeftmostT] {
    // ...implementation of zero, one, add, mult...
  }

However, I had some problems when I had to define a SemiringI instance for LeftmostT:

  implicit val semiringILeftmost = new SemiringI[LeftmostT] {
    // ...implementation of zero, one, add, mult (same as for Semiring[LeftmostT])
    // ...implementation of index
  }

It seemed to me I had to repeat the implementations of the functions already defined in Semiring[LeftmostT], that, of course, would not have been scalable. I searched the web for answers, but I was not able to find them. For example, in https://www.slideshare.net/jdegoes/scalaz-8-a-whole-new-game (slide 7) MonoidInt does not reuse the definition of append from Semigroup, as I expected.

At the end, I managed to find a way to proceed, namely:

  // traits Semiring[S] and SemiringI[S] defined as above

  class semiringLeftmostC extends Semiring[LeftmostT] {
        // ...implementation of zero, one, add, mult...
  }
  implicit val semiringLeftmost = new semiringLeftmostC()

  class semiringILeftmostC extends semiringLeftmostC with SemiringI[LeftmostT] {
        // ...implementation of index
  }

  implicit val semiringILeftmost = new semiringILeftmostC()

but I am not sure it is the best one. Can someone please explain to me whether there are other possibilities to reach the same goals, ie, reusing code in hierarchies of typeclass instances?

Thanks in advance.

Thanks to this post , and the advent of Scala 3, I was able to write a concise version of the class hierarchy:

  trait Semiring[S] {
    def zero: S
    def one: S
    def add(a: S, b: S): S
    def mult(a: S, b: S): S
  }

  trait SemiringI[S] extends Semiring[S] {
    def index(i: Int): S
  }

  given semiringLeftmost: Semiring[LeftmostT] with {
    // implementation of Semiring functions
  }

  given semiringILeftmost: SemiringI[LeftmostT] with {
    export semiringLeftmost.*
    override def index(i: Int): LeftmostT = ??? // actual implementation not relevant
  }

I can infer by the mentioned post, however, that there seems to be no consensus on how to encode typeclass hierarchies in Scala 3. The official documentation examples I found seem to redefine functions in the derived traits ( https://dotty.epfl.ch/docs/reference/contextual/type-classes.html ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM