2016-02-27 22 views
8

Dostałem dziwny błąd kompilatora dotyczący niejawnego, który jest rzeczywiście obecny, ale nie można go znaleźć z jakiegoś powodu. Zbudowałem więc mały test, który odtwarza tajemnicze zachowanie.Dlaczego implikacje wysokiego rzędu są w niektórych przypadkach ignorowane?

trait Hide { 
    type T 
} 
object HideString extends Hide { 
    override type T = String 
} 
object HideBool extends Hide { 
    override type T = Boolean 
} 

Typ prosty używany jako jednoznaczny cel dla niejawnych konwersji.

def id[H <: Hide, C](x : C)(implicit ev : C => H#T) : H#T = ev(x) 
def drop[H <: Hide, C](x : C)(implicit ev : C => H#T) : Int = { 
    println(ev(x)) 
    1 
} 
def idSeq[H <: Hide, C](x : Seq[C])(implicit ev : Seq[C] => Seq[H#T]) : Seq[H#T] = ev(x) 
def dropSeq[H <: Hide, C](x : Seq[C])(implicit ev : Seq[C] => Seq[H#T]) : Int = { 
    println(ev(x)) 
    1 
} 

Metody oparte na niejawnych konwersjach. Jest to w zasadzie matryca 2x2. id metody zwracają typ przekonwertowany, a metody drop używają konwersji wewnętrznie i zwracają pewną stałą. Metody normalne działają na dokładnie niejawnie skonwertowanym typie, a metody Seq działają na sekwencjach.

implicit def exString(x : String) : HideString.type#T = x 
implicit def highString[F[_]](x : F[String]) : F[HideString.type#T] = x 

Przede niejawne konwersje highString jest zdefiniowane z typem wyższego rzędu.

val s1 = id("sdf") 
val s2 = drop("aero") 

val r1 = idSeq(Seq("a", "bc")) 
val r2 = dropSeq(Seq("i", "IO")) 

Próbując faktycznie korzysta konwersji przynosi mi błąd:

ImplicitResolution.scala:98: error: No implicit view available from Seq[String] => Seq[test.implicits.HighReduction.Hide#T]. 
    val r2 = dropSeq(Seq("i", "IO")) 

Tak można podsumować w następujący matrycy:

|  | id | drop | 
|--------+------+------| 
| normal | pass | pass | 
| seq | pass | fail | 

Jeśli użyję precyzyjnie zdefiniowany niejawna konwersja do dropSeq metody zwykle znajduje się:

implicit def seqBool(x : Seq[Boolean]) : Seq[HideBool.type#T] = x 

val a1 = idSeq(Seq(true, false)) 
val a2 = dropSeq(Seq(false, true)) 

A ponadto jeśli jawnie określić niejawny argumentu dropSeq zaczął działać:

val r2i = dropSeq(Seq("i", "IO"))(highString[Seq] _) 

I to jest najdziwniejsze. highString domyślnie pasuje do wszystkich wymagań. Jest zadeklarowany jako implicit, więc powinien go znaleźć kompilator. I w przypadku idSeq jest faktycznie znaleziony. Dlaczego więc jest ignorowany w przypadku dropSeq?

Odpowiedz

1

W twoim przypadku jedyną różnicą między idSeq i dropSeq jest typ zwracany: trafiłeś w jakąś skrzynkę w kompilatorze Scala, która jest warta sygnalizowania społeczności Scala.

Powiedział, że Twój idSeq ma niewłaściwy podpis: H#X nie oznacza typ X dla określonego H typu, ale raczej X dla każdej instancji H (nie ten, który został rozwiązany przez kompilator, zobacz Daniel Sobral wyjaśnienie tutaj What does the `#` operator mean in Scala?)

Co prawdopodobnie chcesz zrobić jest ustalenie relacji pomiędzy H i typu wynikowego, co jest łatwiejsze, jeśli wprowadzi typu aliasy, aby uzyskać bardziej czytelny podpis:

object Hide { 
    type HideAux[X] = Hide { type T = X} 
} 

ty możliwe, następnie przepisz swój kod, np. th jest:

def idSeq[B,H <: HideAux[B], C](x : Seq[C])(implicit ev : Seq[C] => Seq[B]) : Seq[B] = ev(x) 
    def dropSeq[B,H <: HideAux[B], C](x : Seq[C])(implicit ev : Seq[C] => Seq[B]) : Int = { 
    println(ev(x)) 
    1 
    } 

Ten kompilacji kodu, a także zawiadomienie, że jeśli prawidłowo używać rodzajowe i typeclasses, nie trzeba dwa różne sposoby id i idSeq ponieważ dynamiczne zachowanie ma być dostarczone przez samą typeclass.

+2

Byłbym bardziej skłonny przyznać ci nagrodę, jeśli zgłosisz problem dotyczący "przypadku narożnego w kompilatorze Scala", który opisujesz. Sądziłem, że to jakiś przypadek, ale wciąż nie dostarczyłeś wystarczających informacji, aby wiedzieć, czy to jest oczekiwane * zachowanie, albo jeśli to naprawdę błąd w kompilatorze. Byłoby miło, gdybyś pozbył się tej zwisającej '}' ... – DaoWen

+0

Twoje dwie funkcje mają tę samą sygnaturę, z wyjątkiem typu zwracanego, ale używasz podpowiedzi typu dla r1 i r2 (dlatego nie można użyć typu powrotu do niejawnej rozdzielczości). Jeśli możliwe jest rozwiązanie domniemanego dla r1 z dostępnymi informacjami o typie, możliwe jest rozwiązanie domniemanego dla r2: biorąc pod uwagę, że drop działa, a dropSeq nie, najprawdopodobniej problem dotyczy typowych typów i typów odwzorowań. – Edmondo1984

+0

Użycie '-Xlog-implicits' daje kilka interesujących błędów. –

Powiązane problemy