自定义类的 List.sum
Posted
技术标签:
【中文标题】自定义类的 List.sum【英文标题】:List.sum on custom class 【发布时间】:2014-03-14 07:04:43 【问题描述】:我有以下代表 GF2 字段的代码:
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
现在我想调用这个函数:List(One, One, Zero, One).sum
这样会调用GF2._+
进行求和,我该如何实现呢? GF2
应该扩展一些接口还是应该实现类型类技术?
【问题讨论】:
【参考方案1】:你需要一个 Numeric[GF2] 隐式:
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
那么你可以这样做:
println(List(One, One, Zero, One).sum)
// One
【讨论】:
所以这是一个类型类实现的例子,对吧? 但如果我这样做println(List(One, One, One).sum)
它无法找到隐含值,因为它现在是 List[One.type]
。在这种情况下我应该使用List[GF2](One)
还是有更好的方法?
@Anton。就个人而言,我会将它设置为 GF2 是一个类(真的,一个 值类 extends AnyVal
)并且只有 val Zero = new GF2(0)
等。【参考方案2】:
看sum
的签名:
def sum[B >: A](implicit num: Numeric[B]): B
我正要建议你通过提供 Numeric[GF2]
类型的隐式值来使 GF2
成为 Numeric
类型类的成员,但后来我查看了 Numeric
的定义并意识到它包含大量与您必须实施的求和完全无关的操作。
我不喜欢这个,我认为sum
方法应该需要一些更抽象的类型类(也许是一个幺半群?)。
所以,我认为您最好的选择(除非您想实现整个 Numeric
实例)是使用 reduce
(仅适用于非空列表)或 fold
:
yourList.reduce(_ + _)
yourList.fold(Zero)(_ + _)
【讨论】:
这当然是一个选择,但我在编程时有点学习 scala,所以我真的很想知道如何通过sum
方式完成这些事情。【参考方案3】:
您需要为您的 trait 实现一个版本的 Numeric
才能使其工作。有关您需要创建的完整定义,请参阅 here。
object InScope
implicit object GF2Numeric extends Numeric[GF2]
//..your implementation here
sum
在List
上的完整签名实际上是:
def sum(implicit num: Numeric[A])
其中A
是List[A]
的类型。
【讨论】:
完整签名其实是def sum[B <: A](implicit num: Numeric[B]): B
以上是关于自定义类的 List.sum的主要内容,如果未能解决你的问题,请参考以下文章