2014-12-08 21 views
12

Ich tippte die folgenden in die Scala-ERSATZ:Scala: fehlende Parameter Typ

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) 

Warum bin ich für die zweite Zeile einen Fehler zu bekommen? Ist das ein Fehler im Compiler oder fehlt mir etwas?

+3

Ich würde vermuten, dass die '.subsets' mehr mehrdeutig ist (es eine partielle Anwendung der Version sein könnte, das ein Argument), so Art Schlussfolgerung funktioniert weniger gut. In jedem Fall können Sie es kompilieren, indem Sie tun, was der Compiler Ihnen sagt und einen expliziten Typ bereitstellt: 'List (1, 2, 3) .toSetSets.map {x: Set [Int] => x.toList}' – lmm

+1

Die beiden Methoden haben jedoch dieselbe Rückgabesignatur wie in 2.10.4 scaladoc: 'def Untergruppen: Iterator [Set [A]]', 'Def Subsets (len: Int): Iterator [Set [A]]' Also sollte es keinen Unterschied geben, soweit es Typen betrifft , Recht? – the21st

+2

Ist es nicht eine Inkonsistenz in Scala, dass diese Methoden zusammen erlaubt sind, während eine Methode 'def Subsets (i: Int) (d: Double): Iterator [Set [A]]' einen 'mehrdeutigen Verweis auf überladene Definition' verursachen würde Error? –

Antwort

3

Paradoxerweise ist die erste Version funktioniert, weil subsets in der Anwendung subsets(2) ist, wie es war, mehrdeutiger als ohne parens.

Da das Verfahren überlastet ist, in der Anwendung, die Compiler Pausen für das Ergebnis der BtoSet zu lösen, und entscheidet, dass BInt ist. So weiß es, welcher Param-Typ für die map erwartet wird.

In der Version ohne Parens ist die Methode mit einer Parameterliste kein Kandidat, da eta-expansion nicht ausgelöst wird. Wenn es also die map-Anwendung eingibt, hat es keine Rückschlüsse auf B gezogen, die der Eingabetyp für die Zuordnungsfunktion ist.

Die einfache Lösung ist es zu sagen, B ableiten:

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

Der Ausgang des -Ytyper-debug auf dem ursprünglichen Code zeigt, wie die Überladungsauflösung Typinferenz gooses:

| | | | | | \-> => 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]] 

Eine andere Lösung ist zu gehen durch eine Erweiterungsmethode:

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 

Mal sehen, ob sie die Bibliothek ändern nehmen werden:

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

0

Subsets können teilweise Anwendung der anderen Überladung sein.

0

Dies scheint ein Compiler-Problem zu sein.

vergleichen:

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

Dies ist höchstwahrscheinlich selbst ein Compiler Problem sein, dass es Typinferenz nicht tut. Ich habe vorher ein ähnliches Problem.

Wenn Sie einen kurzen Blick auf die Definitionen von subsets() und subsets(len: Int) von Set werfen, teilen sie den gleichen Rückgabetyp, also sollten sie beide funktionieren, richtig?

das Problem zu lösen, das funktioniert:

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

Sie haben 'Untergruppen' falsch angegeben, die keine Param-Liste haben. Sonst gäbe es kein Problem –