2013-03-04 10 views
5

W dzisiejszych czasach uczyłem się Scali, a dziś napotkałem problem, którego nie rozumiem.Problemy z wnioskami typu Scala z funkcją parametryczną

Załóżmy, że mamy następującą parametryczną definicję funkcji:

def filter[T](source: List[T], predicate: T=>Boolean): List[T] = { 
    source match { 
     case Nil => Nil 
     case x::xs => if(predicate(x)) x::filter(xs, predicate) 
        else filter(xs, predicate) 
    } 
} 

Teraz, to działa dobrze, gdy przywołuję go w następujący sposób:

filter(List(1,2,3,4,5,6), ((n:Int) => n % 2 == 0)) 

Ale jeśli usunąć tag typu, wydaje się Scala nie można wywnioskować, że typ T to Int.

filter(List(1,2,3,4,5,6), (n => n % 2 == 0)) 

Tak, jestem zmuszony do podania jawnej informacji o typie w tym wywołaniu.

Czy ktoś wie, dlaczego Scala nie jest w stanie wnioskować o typie T w tym wywołaniu. Lista jest ewidentnie Listą Int, nie rozumiem, dlaczego nie może wywnioskować, że typ n jest również Int.

Odpowiedz

8

Scala rodzaj wnioskowania działa za parametru lista, nie za parametru, więc nie rozwiązany T do Int zanim dojdzie do orzecznika w drugim przykładzie. Można jednak uzyskać to, co chcesz za pomocą dwóch list parametrów:

def filter[T](source: List[T])(predicate: T => Boolean): List[T] = 
    source match { 
    case Nil => Nil 
    case x :: xs => 
     if (predicate(x)) 
     x :: filter(xs)(predicate) 
     else 
     filter(xs)(predicate) 
    } 

teraz następujące będzie działać dobrze:

scala> filter(List(1, 2, 3, 4, 5, 6))((n => n % 2 == 0)) 
res0: List[Int] = List(2, 4, 6) 

Zobacz moją odpowiedź here jakiegoś dodatkowego dyskusji.

+0

Dodatkowo, wywoływanie takich HOF jest w rzeczywistości syntaktycznie bardziej naturalne, gdy predykat jest określony na osobnej liście parametrów (i taki, który ma pojedynczy parametr i jest prawostronny, z wyjątkiem dowolnej listy parametrów niejawnych). To dlatego, że nie musisz zagnieżdżać argumentu funkcji wewnątrz parens listy parametrów zawierającej 'source'. Ze względu na warunek "ma jeden parametr", nie trzeba go w ogóle zamykać w parenach, poza parenami (lub nawiasami klamrowymi), których użyje się do objęcia literału funkcji. –

1

Musisz umieścić predykat w drugiej grupie parametrów, aby uzyskać wnioskowanie do pracy:

def filter[T](source: List[T])(predicate: T=>Boolean): List[T] = { 
    source match { 
     case Nil => Nil 
     case x::xs => if(predicate(x)) x::filter(xs)(predicate) 
        else filter(xs)(predicate) 
    } 
} 

filter(List(1,2,3,4,5,6))(_ % 2 == 0) 

Niestety jest to ograniczenie Scala.