Полиморфное скалярное произведение в Scala и сокращение от анонимной функции - PullRequest
1 голос
/ 28 ноября 2011

Я бы хотел реализовать «матричный продукт» в 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

Какая разница?

Ответы [ 2 ]

3 голосов
/ 28 ноября 2011

указание dot[Real] явно должно работать тоже.

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

РЕДАКТИРОВАТЬ

, отвечая на ваши изменения: я думаю, что проблема в том, что неявное преобразование из Array в WrappedArray не применяется рекурсивно, когда выесть Array[Array].

Array[Int] не является Iterable[Int];обычно, когда вы присваиваете его Iterable, Array[Int] неявно преобразуется в WrappedArray[Int] (где WrappedArray равен Iterable [Int]).Это то, что происходит, когда вы используете List[Array[Int]] (вы получаете List[WrappedArray[Int]] неявно).

Однако, как я уже сказал, неявное преобразование не применяется рекурсивно, поэтому Array[Array[Int]] неявно не преобразуется в WrappedArray[WrappedArray[Int]].

Вот сеанс REPL, который демонстрирует проблему:

Список [Array [Int]] может быть назначен для Iterable [Iterable [Int]] (обратите внимание, что Array преобразуется в 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))

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))
                                              ^

Тем не менее, при некотором удерживании (преобразовании внутренних массивов вручную в 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))
3 голосов
/ 28 ноября 2011

Да - если вы переключаете списки аргументов. Вывод типа для параметров функции работает более эффективно, когда параметр функции находится один в списке последних аргументов:

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)(_*_)
...