2011-07-31 10 views
12

Kiedy próbuję skompilować mały przykład:Rodzaj wywnioskować aby nic w Scala

trait Foo[A,B] { 
    type F[_,_] 
    def foo(): F[A,B] 
} 

class Bar[A,B] extends Foo[A,B] { 
    type F[D,E] = Bar[D,E] 
    def foo() = this 
} 

object Helper { 
    def callFoo[A,B,FF <: Foo[A,B]](f: FF): FF#F[A,B] = 
    f.foo() 
} 

object Run extends App { 
    val x = new Bar[Int,Double] 
    val y = Helper.callFoo(x) 
    println(y.getClass) 
} 

pojawia się błąd:

[error] src/Issue.scala:20: inferred type arguments 
[Nothing,Nothing,issue.Bar[Int,Double]] do not conform to method callFoo's type 
parameter bounds [A,B,FF <: issue.Foo[A,B]] 
[error]  val y = Helper.callFoo(x) 

Najwyraźniej mechanizm typu wnioskowanie nie jest w stanie wyprowadzić i B poza prętem [A, B]. Działa to jednak, gdy ręcznie przekazuję wszystkie typy:

val y = Helper.callFoo[Int,Double,Bar[Int,Double]](x) 

Czy istnieje sposób uniknięcia jawnego przekazywania typów?

Odpowiedz

11

będziesz musiał zmienić podpis callFoo do tego:

def callFoo[A, B, FF[A, B] <: Foo[A, B]](f: FF[A, B]): FF[A, B]#F[A, B] = 

Musisz powiedzieć kompilatorowi, że FF jest rzeczywiście parametryzowanym typem.

+0

@Kipton_Barros: Cóż, wybrałem odpowiedź Jean-Phillipe tylko dlatego, że sugeruje ona mniejszą refaktoryzację moją obecną bazą kodu. – paradigmatic

+0

@paradigmatic Tak, odpowiedź Jean-Philippe'a jest całkiem niezła. Zauważyłem, że interesujące jest to, że chociaż parametr "FF" nie musi mieć wyższego kroka, to pomaga wnioskować. Próbowałem techniki Jean-Philippe'a na pokrewnym pytaniu, ale nie udało mi się, aby to działało do tej pory: http://stackoverflow.com/questions/6892781/why-doesnt-scala-fully-infer-typ--parameters-when- parametry-typu-są-zagnieżdżone/6893057 # 6893057 –

2

Czy zamiast parametrów będą działać elementy typu ?

trait Foo { 
    type A 
    type B 
    type F 
    def foo(): F 
} 

class Bar extends Foo { 
    type F = Bar 
    def foo() = this 
} 

object Helper { 
    def callFoo[FF <: Foo](f: FF): FF#F = 
    f.foo() 
} 

object Run extends App { 
    val x = new Bar{type A=Int; type B=Double} 
    val y = Helper.callFoo(x) 
    println(y.getClass) 
} 

Podczas korzystania członków typ, to warto wiedzieć, że mogą być powierzchniowe jako parametry typu używając wyrafinowania, jak w odpowiedzi Miles Sabin do: Why is this cyclic reference with a type projection illegal?

Zobacz także to ostatnie pytanie, które wydaje się podobne do Ciebie : Scala fails to infer the right type arguments