Inférence de type (F#)
Cette rubrique décrit comment le compilateur F# déduit les types de valeurs, de variables, de paramètres et de valeurs de retour.
Inférence de type en général
L'idée derrière l'inférence de type, c'est de vous permettre de ne pas spécifier les types de constructions F#, sauf lorsque le compilateur ne peut pas déduire le type de façon concluante. L'omission d'informations de type explicite ne signifie pas que F# est un langage typé dynamiquement, ni 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 au cours de la compilation. Si le compilateur ne dispose pas d'informations suffisantes pour déduire les types de chaque construction, vous devez fournir d'autres informations de type, le plus souvent en ajoutant des annotations de type explicite à un endroit du code.
Inférence de types de paramètre et de retour
Dans une liste de paramètres, vous n'êtes pas obligé de spécifier le type de chaque paramètre. Et pourtant, F# étant un langage typé statiquement, chaque valeur et chaque expression ont un type défini au moment de la compilation. Pour les types que vous ne spécifiez pas explicitement, le compilateur déduit le type selon le 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 façon inconsistante, de telle manière qu'aucun type déduit unique ne satisfait à 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 les types de paramètre a et b et le type de retour 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 faites de 100 un uint32 en ajoutant le suffixe u, le compilateur déduit que les types de a, b et de la valeur de retour sont uint32.
Vous pouvez également influencer l'inférence de type à l'aide d'autres constructions qui impliquent des restrictions sur le type, par exemple des fonctions et des méthodes qui fonctionnent avec un seul type particulier.
Vous pouvez de surcroît appliquer des annotations de type explicite aux paramètres de fonction et de méthode ou aux variables dans les expressions, comme indiqué dans les exemples suivants. Des erreurs sont générées si des conflits se produisent entre des contraintes différentes.
// 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 de retour d'une fonction en fournissant une annotation de type après tous les paramètres.
let addu1 x y : uint32 =
x + y
Une annotation de type est utile sur un paramètre 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 fonction n'est pas dépendant du type d'un paramètre, le compilateur considère que le paramètre est générique. Cette approche, appelée généralisation automatique, peut s'avérer très utile pour écrire du code générique sans en augmenter la complexité.
Par exemple, la fonction suivante combine deux paramètres d'un type quelconque dans un tuple.
let makeTuple a b = (a, b)
Le type déduit est le suivant :
'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#.