Il trucco per inferenza dei tipi è quello di considerarla come un processo di raffinamento iterativo. Ogni blocco di parametri può essere utilizzato per dedurre alcuni dei parametri del tipo, che possono essere utilizzati nei blocchi successivi. Quindi prendere la seguente definizione:
def chain[T,A,B](x: T)(fn1: T=>A)(fn2: A=>B) = fn2(fn1(x))
chiamato come:
chain(2)(_*10)("xxx"+_)
Così come questo si deduce? Innanzitutto, iniziamo con il blocco (2)
che è noto per avere il tipo Int
. Sostituendo che torna nel parametro T
otteniamo:
def chain[A,B](x: Int)(fn1: Int=>A)(fn2: A=>B) = fn2(fn1(x))
Il prossimo blocco di parametri è (_*10)
, dove ora sappiamo il tipo di segnaposto _
essere Int
... e moltiplicando un Int
da un Int
dà un'altra Int
. Questo è vero per il tipo restituito anche se si verifica un overflow; all'estremo estremo può generare un'eccezione, ma le eccezioni hanno il tipo Nothing
che è una sottoclasse di tutto il resto nel sistema di tipi, quindi possiamo ancora dire Nothing
è un Int
e il tipo dedotto di Int
è ancora valido.
Con A
dedurre, il metodo diventa:
def chain[B](x: Int)(fn1: Int=>Int)(fn2: Int=>B) = fn2(fn1(x))
solo B
che può essere dedotta da ("xxx"+_)
Partenza.Come String + Int
è un String
, il metodo è ora:
def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String) = fn2(fn1(x))
come il tipo di ritorno del metodo direttamente dal fn2
, che può anche essere indicato esplicitamente per completezza:
def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String): String = fn2(fn1(x))
gioco è fatto , tutti i tipi risolti in modo sicuro e il metodo ha dimostrato di essere staticamente valido.
Nel tuo caso, è necessario il tipo T
da dedurre prima che sia possibile dedurre R
dal tipo T=>R
. Per fare questo devi dividere i parametri in due blocchi distinti, scrivendo il metodo in una forma al curry:
def callOn[T,R](target: T)(f: (T => R)) = f(target)
Grazie per la risposta. Supponiamo di avere questo caso più semplice: 'def callOn4 [R] (f: (Int => R)) = f (4)'. Perché posso omettere il tipo di parametro qui, ma non se lo definisco come 'def callOn4 (f: (Int => _)) = f (4)'? –
@jpp - prova solo a capire quale tipo di ritorno sarebbe dedotto nella tua seconda versione ... –