2015-08-25 41 views
7

Oto prosty program do reprodukcji, w którym definiuję typ "przemiennej" pary, który pochodzi z niejawnej konwersji kolejności. Konwersja niejawna jest stosowana przez kompilator zgodnie z oczekiwaniami, jeśli argument funkcji f znajduje się w istniejącej wcześniej nazwanej wartości (t w przykładzie). Jednak jeśli spróbuję wywołać f bezpośrednio na literalnym CommutativePair, nie powiedzie się z błędem typu. Kompilator nie stosuje w tym przypadku niejawnej konwersji kolejności.Niejawna konwersja Scala jest stosowana w pewnych warunkach, ale nie w innych.

object repro { 
    import scala.language.implicitConversions 

    case class CommutativePair[A, B](a: A, b: B) 

    object CommutativePair { 
    // Support a kind of commutative behavior via an implicit reordering 
    implicit def reorderPair[B, A](pair: CommutativePair[B, A]) = 
     CommutativePair(pair.b, pair.a) 
    } 

    // The idea is to allow a call to 'f' with Pair[Int, String] as well, 
    // via implicit reorder. 
    def f(p: CommutativePair[String, Int]) = p.toString 

    val t = CommutativePair(3, "c") 

    // This works: the implicit reordering is applied 
    val r1 = f(t) 

    // This fails to compile: the implicit reordering is ignored by the compiler 
    val r2 = f(CommutativePair(3, "c")) 
} 
+0

Wnioskowanie o typ wydaje się nie udać; po dodaniu [Int, String] do CommutativePair kompiluje się ponownie. –

+0

@LodewijkBogaards, zgodził się, rozważam zgłoszenie go jako błędu kompilatora scala, ale czekam, aby zobaczyć, jakie otrzymam odpowiedzi. – eje

+0

Powinieneś. Uruchomiłem twój kod w 2.11.7 i otrzymałem ten sam problem. Chociaż mogę sobie wyobrazić, że kompilator ma z tym problem, powinien działać. –

Odpowiedz

2

Uważam, że trafia w ograniczenie wnioskowania scala, wywołane przez kolejność, w której szuka rozwiązań. W pierwszej sytuacji:

val t = CommutativePair(3, "c") 

Wnioskowanie zablokował typ do CommutativePair[Int,String], ponieważ jest jedynym, który może działać w oparciu o parametry. Więc kiedy to nazywa:

val r1 = f(t) 

Robi niezgodność typów na Commutative[Int,String] = = Commutative[String,Int], to wyszukuje implicits i znajdzie jeden powyżej!.

W drugim przypadku, scala próbuje dowiedzieć się, rodzaje, pracuje jego drogę z zewnątrz:

val r2 = f(CommutativePair(3, "c")) 
  • Po pierwsze, to stwierdzi, że f, należy wziąć Commutative[String,Int].
  • Oznacza to, że CommutativePair(...,...)musi być być Commutative[String,Int] (ponieważ, nie zorientowali się, że jest to typ z jego parametrów, jeszcze).
  • Teraz patrzy na parametry do CommutativePair(...) i znajduje je w nieodpowiednim typie. Ale to nie wywoła niejawnej konwersji, ponieważ uważa, że ​​niedopasowanie jest w parametrach, a nie na ogół CommutativePair(...).

Rzeczywiście, paramty typu blokowania (przez podanie ich jawnie lub przez powiązanie z wartością val) naprawiają błąd.