9

Mam fragment kodu, którego nie mogę się zachowywać tak, jak bym chciał. Mam klasy zdefiniowane w następujący sposób (okrojona do tego):Typ argumentu zamknięcia wielu parametrów nie wywnioskowany

class Behaviour[T](private val rule: Time => T) { 
    def map1[U, V](behaviour: Behaviour[U], func: (T, U) => V): Behaviour[V] = { 
    new Behaviour(time => func(this.at(time), behaviour.at(time))) 
    } 
} 

Podczas gry z tej klasy starałem się coś, co myślałem byłoby trywialne:

val beh = Behaviour(time => 5) 
val beh2 = Behaviour(time => 5) 
beh.map1(beh2, (a, b) => a + b) 

Na ostatnim linia i pojawia się następujący błąd:

<console>:13: error: missing parameter type 
      beh.map1(beh2, (a, b) => a + b) 
          ^

mogę oczywiście określić typy parametrów zamknięcia i działa poprawnie, ale dlaczego nie wpisać pracę wnioskowania tutaj? Oczywiście mogłem również określić typy ogólne dla tej funkcji (patrz niżej dla obu rozwiązań).

Myślałem, że Scala przeprowadził "skanowanie", aby wywnioskować typy i zobaczyłby beh2 i przeszedł do funkcji i przyjmie U tutaj, aby być Int. Czy jest jakiś sposób mogę to naprawić bez określenia typów parametrów wejściowych (dla zamknięcia lub generics)?

EDIT: Przykłady dwóch poprawek mam:

beh.map1[Int, Int](beh2, (a, b) => a + b) 
beh.map1(beh2, (a, b : Int) => a + b) 

Odpowiedz

19

Zobacz dyskusję o tym, co się tutaj dzieje, pod numerem this scala-debate thread. Problem polega na tym, że wnioskowanie typu Scala dzieje się na liście parametrów, a nie na parametrze.

Jak zauważa Josh Suereth w tym wątku, istnieje dobry powód obecnego podejścia. Jeśli Scala miał inferencję typów parametrów, kompilator nie mógł wywnioskować górnej granicy pomiędzy typami na tej samej liście parametrów. Rozważmy następujący:

trait X 
class Y extends X 
class Z extends X 

val y = new Y 
val z = new Z 

def f[A](a: A, b: A): (A, A) = (a, b) 
def g[A](a: A)(b: A): (A, A) = (a, b) 

f(y, z) działa dokładnie tak, jak można się było spodziewać, ale g(y)(z) daje niezgodność typów, ponieważ do czasu kompilator ją do drugiej listy argumentów to już wybranego Y jako typ dla A.

4

Jednym ze sposobów, aby to naprawić jest zdefiniowanie wielu list argumentów. Więc metoda map1 byłoby zdefiniowane tak:

def map1[U, V](behaviour: Behaviour[U])(func: (T, U) => V): Behaviour[V] = ... 

i można go używać tak:

beh.map1(beh2)((a, b) => a + b) 
beh.map1(beh2)(_ + _) 

nie jestem całkowicie pewien, dlaczego typ wnioskowanie nie działa w Twoim przypadku, ale wierzę, że ma to coś wspólnego z użyciem parametru typu U. Używasz go dwukrotnie - dla pierwszego i drugiego argumentu. Kompilator prawdopodobnie jest zbyt skomplikowany, aby to rozgryźć. W przypadku 2 list argumentów, U zostanie wywnioskowane podczas kompilacji pierwszej listy argumentów, a druga lista argumentów będzie wykorzystywała już wywnioskowany typ.

+0

Dziękuję bardzo, że działa dobrze! Przyjmuję odpowiedź, jeśli nikt nie może wyjaśnić, co się dzieje następnego dnia. – seadowg

Powiązane problemy