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:
- 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?
- 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?
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-
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.
1 Like
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.
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……