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
?
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
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
Użycie '-Xlog-implicits' daje kilka interesujących błędów. –