I have the following code that represents GF2 field:
trait GF2 {
def unary_- = this
def + (that: GF2): GF2
def * (that: GF2): GF2
def / (that: GF2) = that match {
case Zero => throw new IllegalArgumentException("Div by 0")
case _ => this
}
}
object Zero extends GF2 {
override def toString = "Zero"
def + (that: GF2) = that
def * (that: GF2) = this
}
object One extends GF2 {
override def toString = "One"
def + (that: GF2) = that match { case One => Zero ; case _ => this }
def * (that: GF2) = that match { case One => this ; case _ => that }
}
And now I'd like to call this function: List(One, One, Zero, One).sum
such that GF2._+
would be called for summation, how can I accomplish that? Should GF2
extend some interface or should I implemet type class technique?
You need a Numeric[GF2] implicit:
trait GF2IsNumeric extends Numeric[GF2] {
def plus(x: GF2, y: GF2): GF2 = x + y
def minus(x: GF2, y: GF2): GF2 = x + (-y)
def times(x: GF2, y: GF2): GF2 = x * y
def negate(x: GF2): GF2 = -x
def fromInt(x: Int): GF2 = ???
def toInt(x: GF2): Int = ???
def toLong(x: GF2): Long = ???
def toFloat(x: GF2): Float = ???
def toDouble(x: GF2): Double = ???
override def zero = Zero
override def one = One
}
trait GF2Ordering extends scala.math.Ordering[GF2] {
override def compare(a: GF2, b: GF2) = if (a == b) 0 else if (b == One) 1 else -1
}
implicit object GF2IsNumeric extends GF2IsNumeric with GF2Ordering
Then you can do:
println(List(One, One, Zero, One).sum)
// One
Look at the signature of sum
:
def sum[B >: A](implicit num: Numeric[B]): B
I was about to suggest that you make GF2
a member of Numeric
typeclass by providing and implicit value of type Numeric[GF2]
, but then I looked at the definition of Numeric
and realized that it contains a ton of operations completely irrelevant to summation that you would have to implement.
I don't like this, I think sum
method should require some more abstract typeclass (a monoid, perhaps?).
So, I think your best option (unless you want to implement entire Numeric
instance) is to use either reduce
(will work only with non-empty lists) or fold
:
yourList.reduce(_ + _)
yourList.fold(Zero)(_ + _)
You need to implement a version of Numeric
for your trait in order for it to work. See here for the full definition you'll need to create.
object InScope{
implicit object GF2Numeric extends Numeric[GF2]{
//..your implementation here
}
}
The full signature of sum
on a List
is actually:
def sum(implicit num: Numeric[A])
Where by the A
is the type of the List[A]
.