2014-12-08 6 views
12

я напечатал следующее в Scala-РЕПЛ:Scala: отсутствует параметр типа

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) 

Почему я получаю сообщение об ошибке во второй строке? Это ошибка в компиляторе или я чего-то не хватает?

+3

Я предположил бы, что '.subsets' более неоднозначная (это может быть частичным применением версии, которая принимает аргумент), так типа вывод работает не так хорошо. В любом случае вы можете скомпилировать его, выполнив то, что говорит вам компилятор, и предоставив явный тип: 'List (1, 2, 3) .toSet.subsets.map {x: Установить [Int] => x.toList}' – lmm

+1

Но два метода имеют одну и ту же подпись типа возврата, согласно 2.10.4 scaladoc: 'def subsets: Iterator [Set [A]]', 'def subsets (len: Int): Iterator [Set [A]]' Таким образом, не должно быть никаких различий в отношении типов , правильно? – the21st

+2

Разве это не несогласованность в Scala, что эти методы разрешены вместе, в то время как метод 'def subsets (i: Int) (d: Double): Iterator [Set [A]]' приведет к «неоднозначной ссылке на перегруженное определение» ошибка? –

ответ

3

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

Поскольку метод перегружен, в приложении, компилятор делает паузу, чтобы решить для B результате toSet, и решает, что это BInt. Поэтому он знает, какой тип параметра ожидается для 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

0

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

0

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

Сравнить:

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 
4

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

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

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

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

Вы неверно указали 'subsets', который не имеет списка параметров. В противном случае проблем не было –

Смежные вопросы