Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Funkce jsou základní jednotkou provádění programů v libovolném programovacím jazyce. Stejně jako v jiných jazycích má funkce jazyka F# název, může mít parametry a přijímat argumenty a má tělo. Jazyk F# také podporuje funkční programovací konstrukce, jako je zacházení s funkcemi jako s hodnotami, používání nepojmenovaných funkcí ve výrazech, složení funkcí pro formování nových funkcí, složených funkcí a implicitní definice funkcí prostřednictvím částečného použití argumentů funkce.
Funkce definujete pomocí klíčového let slova, nebo pokud je funkce rekurzivní, let rec kombinace klíčových slov.
Syntaxe
// Non-recursive function definition.
let [inline] function-name parameter-list [: return-type ] = function-body
// Recursive function definition.
let rec function-name parameter-list = recursive-function-body
Poznámky
Název funkce je identifikátor, který představuje funkci. Seznam parametrů se skládá z po sobě jdoucích parametrů oddělených mezerami. Pro každý parametr můžete zadat explicitní typ, jak je popsáno v části Parametry. Pokud nezadáte konkrétní typ argumentu, kompilátor se pokusí odvodit typ z těla funkce. Tělo funkce se skládá z výrazu. Výraz, který tvoří tělo funkce, je obvykle složený výraz sestávající z řady výrazů, které v konečném výrazu vyvrchlí, což je návratová hodnota. Návratový typ je dvojtečka následovaná typem a je nepovinná. Pokud nezadáte typ návratové hodnoty explicitně, kompilátor určí návratový typ z konečného výrazu.
Jednoduchá definice funkce vypadá takto:
let f x = x + 1
V předchozím příkladu je název funkce , argument je fx, který má typ int, tělo funkce je x + 1a návratová hodnota je typu int.
Funkce lze označit inline. Informace o inlinefunkci Inline Functions naleznete v tématu Vložené funkce.
Scope
Na jakékoli úrovni oboru kromě oboru modulu se nejedná o chybu opětovného použití hodnoty nebo názvu funkce. Pokud znovu použijete název, název deklarovaný později stínuje název deklarovaný dříve. V oboru nejvyšší úrovně v modulu však musí být názvy jedinečné. Například následující kód vygeneruje chybu, když se zobrazí v oboru modulu, ale ne, když se zobrazí uvnitř funkce:
let list1 = [ 1; 2; 3 ]
// Error: duplicate definition.
let list1 = []
let function1 () =
let list1 = [ 1; 2; 3 ]
let list1 = []
list1
Následující kód je ale přijatelný na jakékoli úrovni rozsahu:
let list1 = [ 1; 2; 3 ]
let sumPlus x =
// OK: inner list1 hides the outer list1.
let list1 = [ 1; 5; 10 ]
x + List.sum list1
Parametry
Názvy parametrů jsou uvedeny za názvem funkce. Můžete zadat typ parametru, jak je znázorněno v následujícím příkladu:
let f (x: int) = x + 1
Pokud zadáte typ, následuje název parametru a je oddělen od názvu dvojtečka. Pokud typ parametru vynecháte, kompilátor odvozuje typ parametru. Například v následující definici funkce je argument x odvozen jako typ int , protože 1 je typu int.
let f x = x + 1
Kompilátor se však pokusí provést funkci co nejogeneranější. Všimněte si například následujícího kódu:
let f x = (x, x)
Funkce vytvoří řazenou kolekci členů z jednoho argumentu libovolného typu. Vzhledem k tomu, že typ není zadán, lze funkci použít s libovolným typem argumentu. Další informace naleznete v tématu Automatická generalizace.
Těla funkcí
Tělo funkce může obsahovat definice místních proměnných a funkcí. Tyto proměnné a funkce jsou v oboru v těle aktuální funkce, ale ne mimo ni. K označení, že definice je v těle funkce, jak je znázorněno v následujícím příkladu, musíte použít odsazení:
let cylinderVolume radius length =
// Define a local value pi.
let pi = 3.14159
length * pi * radius * radius
Další informace naleznete v tématu Pokyny pro formátování kódu a podrobná syntaxe.
Návratové hodnoty
Kompilátor používá konečný výraz v těle funkce k určení návratové hodnoty a typu. Kompilátor může odvodit typ konečného výrazu z předchozích výrazů. Ve funkci cylinderVolume, která je uvedena v předchozí části, pi typ je určen z typu literálu 3.14159 , který má být float. Kompilátor používá typ pi k určení typu výrazu length * pi * radius * radius , který má být float. Proto je celkový návratový typ funkce float.
Pokud chcete zadat návratový typ explicitně, napište kód následujícím způsobem:
let cylinderVolume radius length : float =
// Define a local value pi.
let pi = 3.14159
length * pi * radius * radius
Jak je kód napsaný výše, kompilátor použije float na celou funkci; Pokud chcete použít i u typů parametrů, použijte následující kód:
let cylinderVolume (radius: float) (length: float) : float
Volání funkce
Funkce voláte tak, že zadáte název funkce následovaný mezerou a potom všechny argumenty oddělené mezerami. Pokud například chcete volat funkci cylinderVolume a přiřadit výsledek k hodnotě vol, napíšete následující kód:
let vol = cylinderVolume 2.0 3.0
Částečné použití argumentů
Pokud zadáte méně než zadaný počet argumentů, vytvoříte novou funkci, která očekává zbývající argumenty. Tato metoda zpracování argumentů se označuje jako currying a je charakteristickou vlastností funkčních programovacích jazyků, jako je F#. Předpokládejme například, že pracujete se dvěma velikostmi potrubí: jeden má poloměr 2,0 a druhý má poloměr 3,0. Můžete vytvořit funkce, které určují objem kanálu následujícím způsobem:
let smallPipeRadius = 2.0
let bigPipeRadius = 3.0
// These define functions that take the length as a remaining
// argument:
let smallPipeVolume = cylinderVolume smallPipeRadius
let bigPipeVolume = cylinderVolume bigPipeRadius
Pak zadáte poslední argument podle potřeby pro různé délky potrubí dvou různých velikostí:
let length1 = 30.0
let length2 = 40.0
let smallPipeVol1 = smallPipeVolume length1
let smallPipeVol2 = smallPipeVolume length2
let bigPipeVol1 = bigPipeVolume length1
let bigPipeVol2 = bigPipeVolume length2
Rekurzivní funkce
Rekurzivní funkce jsou funkce , které volají samy sebe. Vyžadují, abyste zadali klíčové slovo rec za klíčovým slovem let . Vyvolá rekurzivní funkci z těla funkce stejně, jako byste vyvolali jakékoli volání funkce. Následující rekurzivní funkce vypočítá n fibonacciho číslo. Fibonacciho číselná sekvence byla známa od antikvity a je posloupnost, ve které každé po sobě jdoucí číslo je součet předchozích dvou čísel v sekvenci.
let rec fib n =
if n < 2 then 1 else fib (n - 1) + fib (n - 2)
Některé rekurzivní funkce můžou přetékat zásobník programu nebo neefektivně provádět, pokud je nezapisujete opatrně a s vědomím speciálních technik, jako je použití rekurze ocasu, akumulátorů a pokračování.
Hodnoty funkce
V jazyce F# jsou všechny funkce považovány za hodnoty; ve skutečnosti se označují jako hodnoty funkcí. Vzhledem k tomu, že funkce jsou hodnoty, lze je použít jako argumenty pro jiné funkce nebo v jiných kontextech, kde se hodnoty používají. Následuje příklad funkce, která jako argument přebírá hodnotu funkce:
let apply1 (transform: int -> int) y = transform y
Typ hodnoty funkce zadáte pomocí tokenu -> . Na levé straně tohoto tokenu je typ argumentu a na pravé straně je návratová hodnota. V předchozím příkladu je funkce, apply1 která přebírá funkci transform jako argument, kde transform je funkce, která přebírá celé číslo a vrací další celé číslo. Následující kód ukazuje, jak používat apply1:
let increment x = x + 1
let result1 = apply1 increment 100
Hodnota result bude 101 po spuštění předchozího kódu.
Několik argumentů je odděleno následnými -> tokeny, jak je znázorněno v následujícím příkladu:
let apply2 (f: int -> int -> int) x y = f x y
let mul x y = x * y
let result2 = apply2 mul 10 20
Výsledek je 200.
Výrazy lambda
Výraz lambda je nepojmenovaná funkce. V předchozích příkladech můžete místo definování pojmenovaných funkcí inkrementace a mul použít výrazy lambda takto:
let result3 = apply1 (fun x -> x + 1) 100
let result4 = apply2 (fun x y -> x * y) 10 20
Výrazy lambda definujete pomocí klíčového fun slova. Výraz lambda se podobá definici funkce s tím rozdílem, -> že místo = tokenu se token používá k oddělení seznamu argumentů od těla funkce. Stejně jako v definici regulární funkce lze typy argumentů odvodit nebo zadat explicitně a návratový typ výrazu lambda je odvozen z typu posledního výrazu v těle. Další informace naleznete v tématu Výrazy lambda: Klíčové fun slovo.
Pipelines
Operátor potrubí |> se při zpracování dat v jazyce F# používá značně. Tento operátor umožňuje flexibilním způsobem vytvořit kanály funkcí. Pipelining umožňuje zřetězeným voláním funkcí jako následných operací:
let result = 100 |> function1 |> function2
Následující ukázka vás provede postupem vytvoření jednoduchého funkčního kanálu pomocí těchto operátorů:
/// Square the odd values of the input and add one, using F# pipe operators.
let squareAndAddOdd values =
values |> List.filter (fun x -> x % 2 <> 0) |> List.map (fun x -> x * x + 1)
let numbers = [ 1; 2; 3; 4; 5 ]
let result = squareAndAddOdd numbers
Výsledek je [2; 10; 26]. Předchozí ukázka používá funkce zpracování seznamu, které demonstrují, jak lze funkce použít ke zpracování dat při vytváření kanálů. Samotný operátor kanálu je definován v základní knihovně jazyka F#následujícím způsobem:
let (|>) x f = f x
Složení funkce
Funkce v jazyce F# se dají skládat z jiných funkcí. Složení dvou funkcí function1 a function2 je další funkce, která představuje použití funkce1 následované aplikací funkce2:
let function1 x = x + 1
let function2 x = x * 2
let h = function1 >> function2
let result5 = h 100
Výsledek je 202.
Operátor >> složení přebírá dvě funkce a vrací funkci. Naproti tomu operátor |> kanálu přebírá hodnotu a funkci a vrací hodnotu. Následující příklad kódu ukazuje rozdíl mezi kanálem a operátory složení zobrazením rozdílů v podpisech a použití funkce.
// Function composition and pipeline operators compared.
let addOne x = x + 1
let timesTwo x = 2 * x
// Composition operator
// ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3
let Compose2 = addOne >> timesTwo
// Backward composition operator
// ( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
let Compose1 = addOne << timesTwo
// Result is 5
let result1 = Compose1 2
// Result is 6
let result2 = Compose2 2
// Pipelining
// Pipeline operator
// ( |> ) : 'T1 -> ('T1 -> 'U) -> 'U
let Pipeline2 x = addOne x |> timesTwo
// Backward pipeline operator
// ( <| ) : ('T -> 'U) -> 'T -> 'U
let Pipeline1 x = addOne <| timesTwo x
// Result is 5
let result3 = Pipeline1 2
// Result is 6
let result4 = Pipeline2 2
Přetížení funkcí
Můžete přetížit metody typu, ale ne funkce. Další informace naleznete v tématu Metody.