简体   繁体   中英

Type class implementation for hierarchy

I am studying Scala and trying to implement some abstractions for custom types. Defining scalaz monoids for concrete classes is quite straightforward. But how to declare one Monoid for the type hierarchy? Assuming this code:

sealed trait Base
case class A(v:Int) extends Base
object N extends Base

object Main {
  // Wanna one monoid for all the Base's
  implicit val baseMonoid = new Monoid[Base] {
    override def append(f1: Base, f2: => Base): Base = f1 match {
      case A(x) => f2 match {
        case A(y) => A(x + y)
        case N => A(x)
      }
      case N => f2
    }
    override def zero = N
  }

  def main(args: Array[String]): Unit = {
    println(∅[Base] |+| A(3) |+| A(2)) // Compiles
    println(A(3) |+| A(2)) // Not compiles
  }
}

How to make state A() |+| B() workable in the example above?

This compiles:

import scalaz._, Scalaz._

sealed trait Base
case class A(a: Int) extends Base
case class B(b: Int) extends Base
object N extends Base

object BullShit {
  // Wanna one monoid for all the Base's

  implicit val sg: Semigroup[Base] = new Semigroup[Base] {
    override def append(f1: Base, f2: => Base): Base = f1 match {
      case A(a) => f2 match {
        case A(a1) => A(a + a1)
        case B(b) => A(a + b)
        case N => N
      }
      case B(b) => f2 match {
        case A(a) => B(a + b)
        case B(b1) => B(b + b1)
        case N => N
      }
      case N => f2
    }

  }

  println((A(1): Base) |+| (B(2): Base))
}

And your example would compile if you tell Scala's horrible type inferencer what you mean:

sealed trait Base
case class A(v: Int) extends Base
object N extends Base

object Main {
  // Wanna one monoid for all the Base's
  implicit val baseMonoid = new Monoid[Base] {
    override def append(f1: Base, f2: => Base): Base = f1 match {
      case A(x) => f2 match {
        case A(y) => A(x + y)
        case N => A(x)
      }
      case N => f2
    }
    override def zero = N
  }

  def main(args: Array[String]): Unit = {
    import scalaz._, Scalaz._
    println(∅[Base] |+| A(3) |+| A(2)) // Compiles
    println((A(3): Base) |+| (A(2): Base)) // now it compiles
  }
}

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