Share via


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 de 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 do mesmo tipo. Um dos motivos que a função anterior pode ser genérico é que o maior-que o operador (>) é 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 de não-genéricas ou um operador, o 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 de 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-de operador. Portanto, você poderia 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 somente as definições de função completa tem argumentos explícitos e valores imutáveis simples.

Isso significa que o compilador emitirá um erro se você tentar compilar o código que não está suficientemente restrito para ser um tipo específico, mas também não generalizável. A mensagem de erro para esse problema se refere a essa restrição de 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 omitir 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 mais totalmente restringir o problema de inferência de tipo, em uma das seguintes maneiras:

  • Restringir um tipo de 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 incompletos aplicado 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, torne-o em uma função, adicionando um parâmetro extra, não utilizado.

  • Adicione parâmetros de tipo genérico explícito. 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 counter se destina a ser int option ref, mas não está definido como um valor simples imutáveis.

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 da 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: Adicionando parâmetros de tipo.

let emptyset = Set.empty
// Adding a type parameter and type annotation lets you write a generic value.
let emptyset<'a> : Set<'a> = Set.empty

Consulte também

Referência

Inferência de tipo (F#)

Genéricos (F#)

Resolvido estaticamente os parâmetros de tipo (F#)

Restrições (F#)

Histórico de alterações

Date

History

Motivo

Maio de 2010

Código fixo no caso de 2.

Correção de bug de conteúdo.