Тип аргумента закрытия нескольких параметров не выводится - PullRequest
9 голосов
/ 02 февраля 2012

У меня есть кусок кода, который я не могу вести себя так, как мне бы хотелось.У меня есть класс, определенный следующим образом (урезанный для этого):

class Behaviour[T](private val rule: Time => T) {
  def map1[U, V](behaviour: Behaviour[U], func: (T, U) => V): Behaviour[V] = {
    new Behaviour(time => func(this.at(time), behaviour.at(time)))
  }
}

Играя с этим классом, я пытался что-то, что я думал, было бы тривиальным:

val beh = Behaviour(time => 5)
val beh2 = Behaviour(time => 5)
beh.map1(beh2, (a, b) => a + b)

В последней строке я получаю следующую ошибку:

<console>:13: error: missing parameter type
          beh.map1(beh2, (a, b) => a + b)
                             ^

Конечно, я могу указать типы параметров замыкания, и они работают правильно, но почему здесь не работает вывод типов?Конечно, я мог бы также указать универсальные типы для функции (см. Ниже оба решения).

Я думал, что Scala выполнил 'сканирование', чтобы определить типы, и увидел бы beh2 и перешел в функцию и предположил, что U здесь будет Int.Можно ли как-то исправить это без указания типов входных параметров (для замыкания или обобщений)?

РЕДАКТИРОВАТЬ: Примеры двух исправлений, которые у меня есть:

beh.map1[Int, Int](beh2, (a, b) => a + b)
beh.map1(beh2, (a, b : Int) => a + b)

Ответы [ 2 ]

19 голосов
/ 03 февраля 2012

См. этот scala-debate поток для обсуждения того, что здесь происходит. Проблема в том, что вывод типа Scala происходит для списка параметров , а не для параметра .

Как отмечает Джош Суерет в этой теме, есть веская причина для нынешнего подхода. Если Scala имеет вывод типа для каждого параметра, компилятор не может вывести верхнюю границу между типами в одном и том же списке параметров. Учтите следующее:

trait X
class Y extends X
class Z extends X

val y = new Y
val z = new Z

def f[A](a: A, b: A): (A, A) = (a, b)
def g[A](a: A)(b: A): (A, A) = (a, b)

f(y, z) работает точно так, как мы и ожидали, но g(y)(z) дает несоответствие типов, поскольку к тому времени, когда компилятор попадает во второй список аргументов, он уже выбрал Y в качестве типа для A.

4 голосов
/ 02 февраля 2012

Один из способов исправить это - создать несколько списков аргументов.Таким образом, ваш map1 метод будет определен так:

def map1[U, V](behaviour: Behaviour[U])(func: (T, U) => V): Behaviour[V] = ...

, и вы можете использовать его так:

beh.map1(beh2)((a, b) => a + b)
beh.map1(beh2)(_ + _)

Я не совсем уверен, почему вывод типов не работаетв вашем случае, но я считаю, что это как-то связано с использованием параметра типа U.Вы используете его дважды - для первого и второго аргумента.Вероятно, это слишком сложно для компилятора, чтобы понять это.В случае двух списков аргументов U будет выведено во время компиляции первого списка аргументов, а во втором списке аргументов будет использоваться уже выведенный тип.

...