Вывод типов для анонимных функций с помощью rich-my-library

Скажем, у меня есть метод, который превращает (функцию двух элементов) в (функцию двух последовательностей):

def seqed[T](f: (T,T) => T): (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f

Другими словами, результирующая функция берет две последовательности xs и ys и создает новую последовательность, состоящую из (xs(0) f ys(0), xs(1) f ys(1), ...). Так, например, если xss равно Seq(Seq(1,2),Seq(3,4)), а f равно (a: Int, b: Int) => a + b, мы можем вызвать ее следующим образом:

xss reduceLeft seqed(f)         // Seq(4, 6)

или с анонимной функцией:

xss reduceLeft seqed[Int](_+_)

Это очень хорошо; было бы неплохо избавиться от аргумента типа [Int], но я не понимаю, как это сделать (есть идеи?).

Чтобы он немного больше походил на метод tupled, я также попробовал шаблон обогащения моей библиотеки:

class SeqFunction[T](f: (T,T) => T) {
  def seqed: (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f
}
implicit def seqFunction[T](f: (T,T) => T) = new SeqFunction(f)

Для предопределенной функции это прекрасно работает, но с анонимными это некрасиво.

xss reduceLeft f.seqed
xss reduceLeft ((_:Int) + (_:Int)).seqed

Есть ли другой способ переформулировать это так, чтобы типы выводились, и я могу использовать синтаксис примерно так:

// pseudocode
xss reduceLeft (_+_).seqed         // ... or failing that
xss reduceLeft (_+_).seqed[Int]

? Или я слишком много требую от вывода типов?


person Luigi Plinge    schedule 30.11.2011    source источник
comment
Здесь Дэниел Спивак сделал презентацию о системах типов и вывод типа в scala и других языках со статической типизацией. Может быть, это не совсем по теме, но в любом случае, мне было очень интересно.   -  person 4e6    schedule 01.12.2011


Ответы (3)


Вы не можете сделать это так, как хотите, но посмотрите на Function.tupled, который является аналогом .tupled и решает ту же самую проблему.

scala> List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
<console>:8: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
              List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
                                                   ^
<console>:8: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
              List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
                                                       ^

scala> List(1, 2, 3) zip List(1, 2, 3) map Function.tupled(_ + _)
res7: List[Int] = List(2, 4, 6)
person Daniel C. Sobral    schedule 30.11.2011
comment
Подпись Function.tupled - def tupled[a1, a2, b](f: (a1, a2) => b): Tuple2[a1, a2] => b. Что я не могу понять, как он знает типы параметров в приведенном выше примере, тогда как мой метод требует [Int] в xss reduceLeft seqed[Int](_+_). - person Luigi Plinge; 01.12.2011

Я почти уверен, что вы требуете слишком многого. Вывод типов в Scala идет слева направо, поэтому сначала нужно выяснить тип (_+_), прежде чем даже рассматривать часть .sedeq. А там мало информации.

person Alexey Romanov    schedule 30.11.2011

Причина, по которой аннотация типа требуется в

xss reduceLeft seqed[Int](_+_)

но не в

xs zip ys map Function.tupled(_+_)

из-за разницы в требованиях к типу между map и reduceLeft.

def reduceLeft [B >: A] (f: (B, A) ⇒ B): B 
def map        [B]      (f: (A) ⇒ B): Seq[B]   // simple version!

reduceLeft ожидает, что seqed вернет тип B, где B >: Int. Кажется, поэтому точный тип для seqed не может быть известен, поэтому мы должны предоставить аннотацию. Дополнительные сведения см. в этом вопросе.

Один из способов преодолеть это — повторно реализовать reduceLeft без нижней границы.

implicit def withReduceL[T](xs: Seq[T]) = new {
  def reduceL(f: (T, T) => T) = xs reduceLeft f
}

Тестовое задание:

scala> Seq(Seq(1,2,3), Seq(2,2,2)) reduceL seqed(_+_)
res1: Seq[Int] = List(3, 4, 5)

Проблема в том, что теперь это не работает с подтипами Seq (например, List) с параметром [Int] или без него:

scala> Seq(List(1,2,3), List(2,2,2)) reduceL seqed(_+_)
<console>:11: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
              Seq(List(1,2,3), List(2,2,2)) reduceL seqed(_+_)
                                                          ^

reduceL ожидает функцию типа (List[Int], List[Int]) => List[Int]. Поскольку Function2 определяется как Function2 [-T1, -T2, +R], (Seq[Int], Seq[Int]) => Seq[Int] не является допустимой заменой.

person Luigi Plinge    schedule 04.12.2011