How can I describe an this type subjection in Scala?


#1

I wanna to describe a Type which can make add operation, so I defined this trait:
trait Addable[T] {
def +(v: T): T
def zero: T
}
but there’re 2 problems in this code:

  1. One type which should only have one zero element, so maybe I should define zero in object, but there’s not abstract object in scala, how can I define the unique zero in a class?
  2. If I defined a trait: IVector extends Addable[IVector], and I want to make type T of addable should be itself
    It means X extends Addable[Y] is not allowed, you should only use X extends X, what should I do?

#2

For (1), it sounds like you might actually want to make Addable[T] a type
class, rather than a base class for types. The type class instance for a
given T can then provide the zero element.

For (2), i really can’t understand what you’re asking. I think you’re
asking how to make an Addable container IVector require that its
contained elements themselves be Addable? If so, perhaps something like
class IVector[T <: Addable[T]] extends Addable[IVector[T]]
However, if Addable were a typeclass, then you’d instead want to be able
to produce a typeclass instance for IVector[T] given a typeclass instance
for T. This would perhaps be an implicit on IVector's companion
object, although other schemes are possible.

-dave-

#3

At the risk of using difficult words, here are my thoughts

what you need is a Monoid type class and an extra object and implicit class to make mzero and |+| ready for use (they correspond to your zero and +).

trait Monoid[M] {
  def mzero: M

  def mappend(lhs: M, rhs: M): M
}

object Monoid {
  def mzero[M: Monoid]: M = implicitly[Monoid[M]].mzero
}

object Ops {

  implicit class MonoidOps[M: Monoid](lhs: M) {
    def |+|(rhs: M): M = implicitly[Monoid[M]].mappend(lhs, rhs)
  }

}

Now you can define instances

the most common for collections (like List and friends) is

object ListMonoid {
  implicit def listMonoid[M]: Monoid[List[M]] = new Monoid[List[M]] {
    override def mzero: List[M] = List.empty

    override def mappend(lhs: List[M], rhs: List[M]): List[M] = lhs ::: rhs
  }
}

But, from your post, I understand that you want to make use of the fact that M itself is a Monoid.

I guess what you want is

object OtherListMonoid {
  implicit def listMonoid[M: Monoid]: Monoid[List[M]] = new Monoid[List[M]] {
    override def mzero: List[M] = ???

    override def mappend(lhs: List[M], rhs: List[M]): List[M] =
      lhs.zip(rhs).map {
        case (lhs, rhs) => implicitly[Monoid[M]].mappend(lhs, rhs)
      }
  }
}

The problem is that it is not clear what ??? should be.

For stream’s it could be an infinite stream of implicitly[Monoid[M]].mzero's.


#4

It’s hard to understand (because I turned my Abstract Algebra to my teachers) but I believe it may be the solution of my problem and I’m trying to understand it.


#5
  1. How can I ensure there’s only one zero in a class,
    case class DoubleValue(var value: Double) entends Addable {
    override def +(v: DoubleValue) = DoubleValue(value + v.value)
    val zeroVal = DoubleValue(value)
    override def zero = zeroVal
    }
    It’s dumb but every DoubleValue I got have different “zero”.

#6

Thank you and I had defined Addable like this now:

trait Addable[T <: Addable[T]] {
    def +(v: T): T
    def zero:T
}

but there’re some questions to solve……