Подтвердить что ты не робот

Scala: отсутствующий тип параметра

Я набрал следующее в Scala -REPL:

scala> List(1, 2, 3).toSet.subsets(2).map(_.toList)
res0: Iterator[List[Int]] = non-empty iterator

scala> List(1, 2, 3).toSet.subsets.map(_.toList)
<console>:8: error: missing parameter type for expanded function ((x$1) => x$1.toList)
              List(1, 2, 3).toSet.subsets.map(_.toList)

Почему я получаю сообщение об ошибке для второй строки? Является ли это ошибкой в ​​компиляторе или я что-то упускаю?

4b9b3361

Ответ 1

Как ни парадоксально, первая версия работает, потому что subsets в приложении subsets(2) как бы более двусмысленна, чем без парнеров.

Поскольку метод перегружен, в приложении компилятор останавливается для решения для B результата toSet и решает, что B есть Int. Поэтому он знает, какой тип параметра ожидается для map.

В версии без парнеров метод с списком параметров не является кандидатом, потому что эта-расширение не запускается. Поэтому, когда он набирает приложение map, он не сделал никаких выводов о B, который является типом ввода для функции сопоставления.

Легкое исправление заключается в том, чтобы сказать ему, чтобы вывести B:

trait Test {
  def f1 = List(1, 2, 3).to[Set].subsets.map(_.toList) // instead of .toSet
  def f2 = List(1, 2, 3).toSet.subsets(2).map(_.toList)
}

Вывод -Ytyper-debug в исходном коде показывает, как перегрузка разрешает тип вывода типа:

|    |    |    |    |    |    \-> => Iterator[scala.collection.immutable.Set[B]] <and> (len: Int)Iterator[scala.collection.immutable.Set[B]]
|    |    |    |    |    solving for (B: ?B)
|    |    |    |    |    |-- 2 : pt=Int BYVALmode-EXPRmode-POLYmode (silent: method f2 in Test) 
|    |    |    |    |    |    \-> Int(2)
|    |    |    |    |    solving for (B: ?B)
|    |    |    |    |    \-> Iterator[scala.collection.immutable.Set[Int]]

Другим обходным путем является использование метода расширения:

scala> implicit class ss[A](val s: Set[A]) { def ss(n: Int) = s subsets n ; def ss = s.subsets }
defined class ss

scala> List(1, 2, 3).toSet.ss.map(_.toList)
res1: Iterator[List[Int]] = non-empty iterator

Посмотрим, не изменится ли библиотека:

https://github.com/scala/scala/pull/4270

Ответ 2

Это, скорее всего, сама проблема с компилятором, которая не может выполнять вывод типа. Раньше у меня была аналогичная проблема.

Если вы быстро взглянете на определения подмножества() и subsets (len: Int) Set, они имеют один и тот же тип возврата, поэтому они должны работать, правильно?

Чтобы решить проблему, это будет работать:

(List(1, 2, 3).toSet.subsets: Iterator[Set[Int]]).map(_.toList)

Ответ 3

Подмножества могут быть частичным применением другой перегрузки.

Ответ 4

Это проблема компилятора.

Для сравнения:

scala> List(1,2,3).toSet.subsets
res4: Iterator[scala.collection.immutable.Set[Int]] = non-empty iterator

scala> res4.map(_.toList)
res5: Iterator[List[Int]] = non-empty iterator