Automatická generalizace

Jazyk F # používá odvození typu pro vyhodnocení typů funkcí a výrazů. Toto téma popisuje, jak jazyk F # automaticky generalizuje argumenty a typy funkcí tak, aby fungovaly s více typy, pokud je to možné.

Automatická generalizace

Kompilátor F # při provádění typu odvození u funkce určuje, zda daný parametr může být obecný. Kompilátor prověřuje každý parametr a určí, zda má funkce závislost na konkrétním typu daného parametru. Pokud tomu tak není, typ je odvozen jako obecný.

Následující příklad kódu ukazuje funkci, která kompilátor odvodí jako obecný.

let max a b = if a > b then a else b

Typ je odvozený 'a -> 'a -> 'a .

Typ označuje, že se jedná o funkci, která přijímá dva argumenty stejného neznámého typu a vrací hodnotu stejného typu. Jedním z důvodů, proč může být funkce Previous obecná, je, že operátor větší než ( > ) je obecný. Operátor větší než má signaturu 'a -> 'a -> bool . Ne všechny operátory jsou obecné a pokud kód ve funkci používá typ parametru společně s neobecnou funkcí nebo operátorem, tento typ parametru nejde zobecnit.

Vzhledem k tomu, že max je obecný, lze použít s typy int , jako jsou, float a tak dále, jak je znázorněno v následujících příkladech.

let biggestFloat = max 2.0 3.0
let biggestInt = max 2 3

Dva argumenty však musí být stejného typu. Podpis není 'a -> 'a -> 'a 'a -> 'b -> 'a . Proto následující kód vytvoří chybu, protože typy se neshodují.

// Error: type mismatch.
let biggestIntFloat = max 2.0 3

maxFunkce také funguje s jakýmkoli typem, který podporuje operátor větší než. Proto jej můžete použít také na řetězec, jak je znázorněno v následujícím kódu.

let testString = max "cab" "cat"

Omezení hodnoty

Kompilátor provádí automatickou generalizaci pouze v úplných definicích funkcí, které mají explicitní argumenty a na jednoduchých neměnných hodnotách.

To znamená, že kompilátor vyvolá chybu, pokud se pokusíte zkompilovat kód, který není dostatečně omezený na konkrétní typ, ale není možné jej zobecnit. Chybová zpráva pro tento problém odkazuje na toto omezení automatické generalizace pro hodnoty jako omezení hodnoty.

Obvykle dojde k chybě omezení hodnoty, pokud chcete, aby konstrukce byla obecná, ale kompilátor nemá dostatek informací pro generalizaci, nebo Pokud neúmyslně vynecháte dostatečné informace o typu v neobecném konstruktoru. Řešení chyby omezení hodnoty je poskytnout explicitní informace pro větší omezení problému typu odvození typu jedním z následujících způsobů:

  • Omezení typu na neobecný přidáním anotace explicitního typu k hodnotě nebo parametru.

  • Pokud problém používá nezobecnitelné konstrukce k definování obecné funkce, jako je například složení funkce nebo nedokončené použití argumentů funkce curryfikované, zkuste funkci přepsat jako běžnou definici funkce.

  • Pokud je problém výrazem, který je příliš složitý, aby jej bylo možné zobecnit, udělejte ho do funkce přidáním nadbytečného, nepoužívaného parametru.

  • Přidejte explicitní parametry obecného typu. Tato možnost se používá zřídka.

  • Následující příklady kódu ilustrují každý z těchto scénářů.

Případ 1: příliš složitý výraz. V tomto příkladu counter je seznam určen int option ref jako, ale není definován jako jednoduchá neměnná hodnota.

let counter = ref None
// Adding a type annotation fixes the problem:
let counter : int option ref = ref None

Případ 2: použití negeneralizované konstrukce k definování obecné funkce. V tomto příkladu je konstrukce negeneralizovaná, protože zahrnuje částečnou aplikaci argumentů funkce.

let maxhash = max << hash
// The following is acceptable because the argument for maxhash is explicit:
let maxhash obj = (max << hash) obj

Případ 3: přidání nadbytečného, nepoužívaného parametru Vzhledem k tomu, že tento výraz není pro generalizaci dostatečně jednoduchý, vyvolá kompilátor chybu omezení hodnoty.

let emptyList10 = Array.create 10 []
// Adding an extra (unused) parameter makes it a function, which is generalizable.
let emptyList10 () = Array.create 10 []

Případ 4: Přidání parametrů typu

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)

V posledním případě se hodnota stala funkcí typu, která může být použita k vytvoření hodnot mnoha různých typů, například následujícím způsobem:

let intLists = arrayOf10Lists<int>
let floatLists = arrayOf10Lists<float>

Viz také