简体   繁体   English

Scala中的多态点积和匿名函数速记

[英]Polymorphic dot product in Scala and anonymous function shorthand

I'd like to implement a "matrix dot product" in Scala in the following way: 我想通过以下方式在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)

However, the definition of rowDot doesn't work. 但是,rowDot的定义不起作用。 Scala needs explicit type annotations for the anonymous function (_*_) , so instead I must write Scala需要匿名函数(_*_)显式类型注释,所以我必须写

def rowDot(r1: Row, r2: Row) = dot((x:Real, y: Real) => x*y)(r1, r2)

or 要么

def rowDot = dot((x:Real, y: Real) => x*y) _

Is there some way to change the definition of dot so that the shorthand (_*_) can be used? 有什么方法可以更改点的定义,以便可以使用速记(_*_)

Edit: Another confusion: matDot also gives type errors in certain circumstances. 编辑:另一个困惑:matDot在某些情况下还会给出类型错误。 It fails with Arrays of Arrays, but not with Lists of Arrays 对于数组数组失败,但对数组列表失败

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

What's the difference? 有什么不同?

Yes - if you switch your argument lists around. 是的-如果您切换参数列表。 Type inference on function parameters works more effectively when the function parameter is alone in the last argument list: 当最后一个参数列表中单独存在函数参数时,对函数参数的类型推断将更有效地工作:

def dot[T](as: Iterable[T], bs: Iterable[T])(f: (T,T) => Real): Real =
  (for ((a, b) <- as zip bs) yield f(a, b)) sum

def rowDot(r1: Row, r2: Row) = dot(r1, r2)(_*_)

specifying dot[Real] explicitly should work too. 明确指定dot[Real]应该起作用。

def rowDot(r1: Row, r2: Row) = dot[Real](_*_)(r1, r2)

EDIT 编辑

replying to your edit: I think the issue is that the implicit conversion from Array to WrappedArray is not applied recursively when you have a Array[Array] . 回复您的编辑:我认为问题是当您拥有Array[Array]时,无法递归应用从ArrayWrappedArray的隐式转换。

Array[Int] is not an Iterable[Int] ; Array[Int]不是Iterable[Int] normally, when you assign it to a Iterable, an Array[Int] is implicitly converted to a WrappedArray[Int] (where WrappedArray is a Iterable[Int]). 通常,当您将其分配给Iterable时, Array[Int]会隐式转换为WrappedArray[Int] (其中WrappedArray Iterable [Int])。 This is what happens when you use List[Array[Int]] (you get a List[WrappedArray[Int]] implicitly). 当您使用List[Array[Int]] (隐式获得List[WrappedArray[Int]] )时,会发生这种情况。

However, as I said, the implicit conversion is not applied recursively, so an Array[Array[Int]] is not implicitly converted to WrappedArray[WrappedArray[Int]] . 但是,正如我所说,隐式转换不是递归应用的,因此Array[Array[Int]]不会隐式转换为WrappedArray[WrappedArray[Int]]

Here's a REPL session that demonstrates the problem: 这是一个演示该问题的REPL会话:

A List[Array[Int]] can be assigned to Iterable[Iterable[Int]] (note that Array is converted to WrappedArray) 可以将List [Array [Int]]分配给Iterable [Iterable [Int]](请注意,数组已转换为WrappedArray)

scala> val i : Iterable[Iterable[Int]] = List(Array(1,2), Array(1,2,3))
i: Iterable[Iterable[Int]] = List(WrappedArray(1, 2), WrappedArray(1, 2, 3))

An Array[Array[Int]] does not work automatically (as you discovered) Array [Array [Int]]无法自动运行(如您所发现的)

scala> val j : Iterable[Iterable[Int]] = Array(Array(1,2), Array(1,2,3))
<console>:9: error: type mismatch;
 found   : Array[Array[Int]]
 required: Iterable[Iterable[Int]]
       val j : Iterable[Iterable[Int]] = Array(Array(1,2), Array(1,2,3))
                                              ^

However, with some hand-holding (converting manually the inner Arrays to WrappedArrays) everything works again: 但是,通过一些手动操作(将内部Array手动转换为WrappedArrays),一切又可以正常工作:

    scala> import scala.collection.mutable.WrappedArray
    import scala.collection.mutable.WrappedArray

    scala> val k : Iterable[Iterable[Int]] = Array(WrappedArray.make(Array(1,2)),
 WrappedArray.make(Array(1,2,3)))
    k: Iterable[Iterable[Int]] = WrappedArray(WrappedArray(1, 2), WrappedArray(1, 2,
     3))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM