Inferenza di tipi

Questo argomento descrive in che modo il compilatore F# deduce i tipi di valori, variabili, parametri e valori restituiti.

Inferenza dei tipi in generale

L'idea di inferenza del tipo è che non è necessario specificare i tipi di costrutti F# tranne quando il compilatore non può dedurre definitivamente il tipo. L'omissione di informazioni esplicite sul tipo non significa che F# è un linguaggio tipizzato in modo dinamico o che i valori in F# sono tipizzati in modo debole. F# è un linguaggio tipizzato in modo statico, il che significa che il compilatore deduce un tipo esatto per ogni costrutto durante la compilazione. Se il compilatore non contiene informazioni sufficienti per dedurre i tipi di ogni costrutto, è necessario fornire informazioni aggiuntive sul tipo, in genere aggiungendo annotazioni di tipo esplicite in un punto qualsiasi del codice.

Inferenza di parametri e tipi restituiti

In un elenco di parametri non è necessario specificare il tipo di ogni parametro. F# è tuttavia un linguaggio tipizzato in modo statico e pertanto ogni valore e espressione ha un tipo definito in fase di compilazione. Per questi tipi che non si specificano in modo esplicito, il compilatore deduce il tipo in base al contesto. Se il tipo non è specificato in altro modo, viene dedotto come generico. Se il codice usa un valore in modo incoerente, in modo che non esista un singolo tipo dedotto che soddisfi tutti gli usi di un valore, il compilatore segnala un errore.

Il tipo restituito di una funzione è determinato dal tipo dell'ultima espressione nella funzione.

Nel codice seguente, ad esempio, i tipi di a parametro e b il tipo restituito vengono dedotti perché int il valore letterale 100 è di tipo int.

let f a b = a + b + 100

È possibile influenzare l'inferenza del tipo modificando i valori letterali. Se si crea un oggetto 100 aggiungendo il suffisso u, i tipi di a, be il valore restituito vengono dedotti come uint32.uint32

È anche possibile influenzare l'inferenza dei tipi usando altri costrutti che implicano restrizioni sul tipo, ad esempio funzioni e metodi che funzionano solo con un particolare tipo.

È anche possibile applicare annotazioni di tipo esplicite ai parametri della funzione o del metodo o alle variabili nelle espressioni, come illustrato negli esempi seguenti. Gli errori generano errori se si verificano conflitti tra vincoli diversi.

// Type annotations on a parameter.
let addu1 (x : uint32) y =
    x + y

// Type annotations on an expression.
let addu2 x y =
    (x : uint32) + y

È anche possibile specificare in modo esplicito il valore restituito di una funzione fornendo un'annotazione di tipo dopo tutti i parametri.

let addu1 x y : uint32 =
   x + y

Un caso comune in cui un'annotazione di tipo è utile per un parametro è quando il parametro è un tipo di oggetto e si vuole usare un membro.

let replace(str: string) =
    str.Replace("A", "a")

Generalizzazione automatica

Se il codice della funzione non dipende dal tipo di un parametro, il compilatore considera il parametro generico. Questa operazione è detta generalizzazione automatica e può essere un potente aiuto per scrivere codice generico senza aumentare la complessità.

Ad esempio, la funzione seguente combina due parametri di qualsiasi tipo in una tupla.

let makeTuple a b = (a, b)

Il tipo viene dedotto come

'a -> 'b -> 'a * 'b

Informazioni aggiuntive

L'inferenza dei tipi è descritta in modo più dettagliato nella specifica del linguaggio F#.

Vedi anche