Inférence de type

Cette rubrique décrit comment le compilateur F# déduit les types de valeurs, variables, paramètres et valeurs renvoyées.

Inférence de type en général

L’idée de l’inférence de type est que vous n’avez pas besoin de spécifier les types des constructions F#, sauf lorsque le compilateur ne peut pas les déduire de manière concluante. L’omission d’informations de type explicites ne signifie pas que F# est un langage typé dynamiquement ou que les valeurs en F# sont faiblement typées. F# est un langage typé statiquement, ce qui signifie que le compilateur déduit un type exact pour chaque construction pendant la compilation. Si le compilateur ne dispose pas de suffisamment d’information pour déduire les types de chaque construction, vous devez fournir des informations de type supplémentaires, généralement en ajoutant des annotations de type explicites quelque part dans le code.

Inférence des types de paramètre et de retour

Dans une liste de paramètres, vous n’avez pas besoin de spécifier le type de chaque paramètre. Et pourtant, F# est un langage typé statiquement. Par conséquent, chaque valeur et expression a un type défini au moment de la compilation. Pour les types que vous ne spécifiez pas explicitement, le compilateur les déduit en fonction du contexte. Si le type n’est pas spécifié autrement, le compilateur déduit qu’il est générique. Si le code utilise une valeur de manière incohérente, de telle sorte qu’il n’est pas possible de déduire un type unique répondant à toutes les utilisations d’une valeur, le compilateur signale une erreur.

Le type de retour d’une fonction est déterminé par le type de la dernière expression dans la fonction.

Par exemple, dans le code suivant, le compilateur déduit que le type de retour et les types de paramètres a et b sont tous int, car le littéral 100 est de type int.

let f a b = a + b + 100

Vous pouvez influencer l’inférence de type en modifiant les littéraux. Si vous transformez le littéral 100 en un type uint32 en ajoutant le suffixe u, le compilateur déduit que les types de a, de b et de la valeur renvoyée sont uint32.

Vous pouvez également influencer l’inférence de type en utilisant d’autres constructions qui impliquent des restrictions de type, telles que des fonctions et des méthodes qui fonctionnent uniquement avec un type particulier.

En outre, vous pouvez appliquer des annotations de type explicites à des paramètres de fonction ou de méthode ou à des variables dans des expressions, comme illustré dans les exemples suivants. Des erreurs se produisent en cas de conflits entre différentes contraintes.

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

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

Vous pouvez également spécifier explicitement la valeur renvoyée d’une fonction en fournissant une annotation de type après tous les paramètres.

let addu1 x y : uint32 =
   x + y

Cas courant où l’application d’une annotation de type sur un paramètre est utile : lorsque le paramètre est un type d’objet et que vous souhaitez utiliser un membre.

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

Généralisation automatique

Si le code de la fonction ne dépend pas du type d’un paramètre, le compilateur considère le paramètre comme générique. C’est ce qu’on appelle la généralisation automatique. C’est un outil puissant pour vous aider à écrire du code générique sans augmenter la complexité.

Par exemple, la fonction suivante combine deux paramètres de n’importe quel type dans un tuple.

let makeTuple a b = (a, b)

Le type est déduit comme étant

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

Informations supplémentaires

L’inférence de type est décrite plus en détail dans la spécification du langage F#.

Voir aussi