我正在学习Scala,并尝试实现一些自定义类型的抽象。为具体类定义scalaz monoids非常简单。但是如何为类型层次结构声明一个Monoid呢?假设代码如下:
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
}
}
在上面的例子中如何使状态A() |+| B()可行?
下面编译:
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))
}
如果你告诉Scala可怕的类型推断器你的意思,你的例子就会编译:
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
}
}