【发布时间】:2012-01-08 02:32:51
【问题描述】:
我想通过以下方式在 Scala 中实现“矩阵点积”:
type Real = Double
type Row = Array[Real]
type Matrix = Array[Row]
def dot[T](f: (T,T) => Real)(as: Iterable[T], bs: Iterable[T]): Real =
(for ((a, b) <- as zip bs) yield f(a, b)) sum
def rowDot(r1: Row, r2: Row) = dot(_*_)(r1, r2)
def matDot(m1: Matrix, m2: Matrix) = dot(rowDot)(m1, m2)
但是,rowDot 的定义不起作用。 Scala 需要对匿名函数 (_*_) 进行显式类型注释,所以我必须编写
def rowDot(r1: Row, r2: Row) = dot((x:Real, y: Real) => x*y)(r1, r2)
或
def rowDot = dot((x:Real, y: Real) => x*y) _
有没有办法改变点的定义,以便使用简写(_*_)?
编辑:另一个困惑:matDot 在某些情况下也会给出类型错误。它在数组数组中失败,但在数组列表中失败
scala> matDot(Array(Array(1.0,2.0)), Array(Array(1.0,2.0,3.0)))
<console>:27: error: type mismatch;
found : Array[Array[Double]]
required: Iterable[Iterable[Real]]
matDot(Array(Array(1.0,2.0)), Array(Array(1.0,2.0,3.0)))
^
scala> matDot(List(Array(1.0,2.0)), List(Array(1.0,2.0,3.0)))
res135: Real = 5.0
有什么区别?
【问题讨论】:
-
只是一个警告:您编写的代码中有很多装箱和拆箱。它会起作用,但不会很快。
-
很高兴知道。你能指出我改进它的正确方向吗?在使用它的代码中,我以一种重要的方式利用了具有不同长度列表的 zip 行为,因此我宁愿不简单地使用一些专用的线性代数库。
-
不幸的是,没有好的方向。当在这两个目标之间进行权衡时,Scala 的库旨在实现最大的表达能力,而不是最大的计算效率。您可以查看 Scalala 的原生 Scala 线性代数包,或各种 Java 包(基准为 code.google.com/p/java-matrix-benchmark/wiki/…),您提供的包装器还实现了您需要的功能(例如 zip)。但是,如果矩阵运算的性能并不重要,您可能不必担心。
-
我刚刚看到(并试图回答)您的编辑
标签: scala types polymorphism anonymous-function