Generalização automática (F#)
F# usa a inferência de tipos para avaliar os tipos de funções e expressões.Este tópico descreve como F# automaticamente generaliza os argumentos e os tipos de funções para que funcionem com vários tipos de quando isso for possível.
Generalização automática
O compilador F#, quando ele executa a inferência de tipo em uma função, determina se um determinado parâmetro pode ser genérico.O compilador examina cada parâmetro e determina se a função tem uma dependência no tipo específico de parâmetro.Se não tiver, o tipo é inferido para ser genérico.
O exemplo de código a seguir ilustra uma função que o compilador infere ser genérico.
let max a b = if a > b then a else b
O tipo é inferido para ser 'a -> 'a -> 'a.
O tipo indica que se trata de uma função que leva dois argumentos do mesmo tipo desconhecido e retorna um valor desse mesmo tipo.Um dos motivos que a função anterior pode ser genérico é que o maior-que o operador (>) é o próprio genérico.Maior-que o operador tem a assinatura 'a -> 'a -> bool.Nem todos os operadores são genéricos e se o código em uma função usa um tipo de parâmetro junto com uma função não genérico ou um operador, esse tipo de parâmetro não pode ser generalizado.
Porque max é genérica, ele pode ser usado com tipos como int, floate assim por diante, conforme mostrado nos exemplos a seguir.
let biggestFloat = max 2.0 3.0
let biggestInt = max 2 3
No entanto, os dois argumentos devem ser do mesmo tipo.A assinatura é 'a -> 'a -> 'a, e não 'a -> 'b -> 'a.Portanto, o código a seguir produz um erro porque os tipos não coincidem.
// Error: type mismatch.
let biggestIntFloat = max 2.0 3
O max função também funciona com qualquer tipo que ofereça suporte a maior-que o operador.Portanto, você pode também usá-lo em uma seqüência de caracteres, conforme mostrado no código a seguir.
let testString = max "cab" "cat"
Restrição de valor
O compilador executa generalização automática apenas em definições de função completa com argumentos explícitos e nos valores imutáveis simples.
Isso significa que o compilador emitirá um erro se você tentar compilar o código que não é suficientemente restrito a ser um tipo específico, mas também não é generalizável.A mensagem de erro para esse problema refere-se a essa restrição no generalização automática para valores como o a restrição de valor.
Normalmente, o erro de restrição de valor ocorre quando você deseja que uma construção ser genérico, mas o compilador não tem informações suficientes para generalizar a ele, ou quando você omite involuntariamente suficientes informações de tipo em uma construção não genérico.A solução para o erro de restrição de valor é fornecer informações mais explícitas para totalmente restringir o problema de inferência de tipo, em uma das seguintes maneiras:
Restringir um tipo a ser não genérico, adicionando uma anotação de tipo explícito para um valor ou parâmetro.
Se o problema estiver usando uma construção de nongeneralizable para definir uma função genérica, como, por exemplo, uma composição de função ou parcialmente aplicada argumentos da função curried, tente reescrever a função como uma definição de função comum.
Se o problema é uma expressão que é muito complexa para ser generalizada, torná-lo em uma função, adicionando um parâmetro extra, não utilizado.
Adicione parâmetros de tipo genérico explícita.Esta opção é usada raramente.
Os exemplos de código a seguir ilustram a cada um desses cenários.
Caso 1: Uma expressão muito complexa.Neste exemplo, a lista de counter deve ser int option ref, mas ele não está definido como um valor imutável simple.
let counter = ref None
// Adding a type annotation fixes the problem:
let counter : int option ref = ref None
Caso 2: Usando uma construção de nongeneralizable para definir uma função genérica.Neste exemplo, a construção é nongeneralizable porque envolve a aplicação parcial de argumentos da função.
let maxhash = max << hash
// The following is acceptable because the argument for maxhash is explicit:
let maxhash obj = (max << hash) obj
Caso 3: Adicionando um parâmetro extra, não utilizado.Como esta expressão não é simple o suficiente para generalização, o compilador emitirá o erro de restrição de valor.
let emptyList10 = Array.create 10 []
// Adding an extra (unused) parameter makes it a function, which is generalizable.
let emptyList10 () = Array.create 10 []
Caso 4: Adicionar tipos de parâmetros.
let arrayOf10Lists = Array.create 10 []
// Adding a type parameter and type annotation lets you write a generic value.
let arrayOf10Lists<'T> = Array.create 10 ([]:'T list)
Nesse último caso, o valor torna-se uma função de tipo, que pode ser usada para criar valores de muitos tipos diferentes, por exemplo, da seguinte maneira:
let intLists = arrayOf10Lists<int>
let floatLists = arrayOf10Lists<float>