Megosztás a következőn keresztül:


Functions

A függvények a program végrehajtásának alapvető egységei bármely programozási nyelven. Más nyelvekhez hasonlóan az F#-függvényeknek is van neve, lehetnek paramétereik, argumentumokat vehetnek fel, és törzsük is van. Az F# olyan funkcionális programozási szerkezeteket is támogat, mint például a függvények értékként való kezelése, a kifejezésekben névtelen függvények használata, új függvények kialakítására szolgáló függvények összetétele, curriált függvények és a függvények implicit definíciója a függvényargumentumok részleges alkalmazásával.

A függvények definiálásához használja a let kulcsszót, vagy ha a függvény rekurzív, a let rec kulcsszókombinációt.

Syntax

// 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

Megjegyzések

A függvény neve egy olyan azonosító, amely a függvényt jelöli. A paraméterlista szóközökkel elválasztott egymást követő paraméterekből áll. Minden paraméterhez megadhat egy explicit típust a Paraméterek szakaszban leírtak szerint. Ha nem ad meg egy adott argumentumtípust, a fordító megpróbálja kikövetkeztetni a típust a függvény törzséből. A függvénytörzs egy kifejezésből áll. A függvény törzsét alkotó kifejezés általában egy összetett kifejezés, amely több olyan kifejezésből áll, amelyek a visszatérési értéket tartalmazó végső kifejezésben csúcsosulnak ki. A visszatérési típus egy kettőspont, amelyet egy típus követ, és nem kötelező. Ha nem adja meg explicit módon a visszatérési érték típusát, a fordító határozza meg a visszatérési típust a végső kifejezésből.

Egy egyszerű függvénydefiníció a következőhöz hasonló:

let f x = x + 1

Az előző példában a függvény neve f, az argumentum, xamelynek típusa int, a függvény törzse x + 1, a visszatérési érték pedig típus int.

A függvények megjelölhetők inline. További információ: inlineBeágyazott függvények.

Hatókör

A modul hatókörétől eltérő hatókörszinten nem hiba egy érték vagy függvénynév újbóli felhasználása. Ha újra felhasznál egy nevet, a később deklarált név árnyékot ad a korábban deklarált névnek. A modulok legfelső szintű hatókörében azonban a neveknek egyedinek kell lenniük. A következő kód például hibát eredményez, amikor a modul hatókörében jelenik meg, de nem, ha egy függvényben jelenik meg:

let list1 = [ 1; 2; 3]
// Error: duplicate definition.
let list1 = []
let function1 () =
   let list1 = [1; 2; 3]
   let list1 = []
   list1

A következő kód azonban bármely hatókörszinten elfogadható:

let list1 = [ 1; 2; 3]
let sumPlus x =
// OK: inner list1 hides the outer list1.
   let list1 = [1; 5; 10]
   x + List.sum list1

Paraméterek

A paraméterek nevei a függvény neve után jelennek meg. A paraméter típusát az alábbi példában látható módon adhatja meg:

let f (x : int) = x + 1

Ha megad egy típust, az a paraméter nevét követi, és kettőspont választja el a névtől. Ha kihagyja a paraméter típusát, a paramétertípust a fordító kikövetkezteti. Az alábbi függvénydefinícióban például az argumentum x típusra int van kikövetkeztetve, mert az 1 típus int.

let f x = x + 1

A fordító azonban megpróbálja a lehető leggenerikusabbá tenni a függvényt. Jegyezze fel például a következő kódot:

let f x = (x, x)

A függvény bármilyen típusú argumentumból rekordot hoz létre. Mivel a típus nincs megadva, a függvény bármilyen argumentumtípussal használható. További információ: Automatikus általánosítás.

Függvénytestek

A függvénytörzsek helyi változók és függvények definícióit tartalmazhatják. Az ilyen változók és függvények hatóköre az aktuális függvény törzsében található, de azon kívül nem. Behúzással kell jeleznie, hogy egy definíció egy függvénytörzsben található, ahogy az alábbi példában látható:

let cylinderVolume radius length =
    // Define a local value pi.
    let pi = 3.14159
    length * pi * radius * radius

További információ: Kódformázási irányelvek és részletes szintaxis.

Értékeket ad vissza

A fordító a függvény törzsében lévő végső kifejezést használja a visszatérési érték és a típus meghatározásához. Előfordulhat, hogy a fordító a korábbi kifejezésekből származó végső kifejezés típusát következteti. Az előző szakaszban látható függvényben cylinderVolumea függvény típusa pi a konstans 3.14159 típusából lesz meghatározva float. A fordító a kifejezés típusának pi meghatározására használja a típust length * pi * radius * radiusfloat. Ezért a függvény általános visszatérési típusa .float

A visszatérési típus explicit megadásához írja be a kódot a következő módon:

let cylinderVolume radius length : float =
   // Define a local value pi.
   let pi = 3.14159
   length * pi * radius * radius

Ahogy a kód fent meg van írva, a fordító a teljes függvényre alkalmazza a lebegőpontos kódot; ha a paramétertípusokra is alkalmazni szeretné, használja a következő kódot:

let cylinderVolume (radius : float) (length : float) : float

Függvény meghívása

A függvényeket úgy hívhatja meg, hogy megadja a függvény nevét, majd egy szóközt, majd az argumentumokat szóközök választják el egymástól. Ha például meghívja a cylinderVolume függvényt, és hozzárendeli az eredményt az vol értékhez, a következő kódot kell írnia:

let vol = cylinderVolume 2.0 3.0

Argumentumok részleges alkalmazása

Ha a megadott számú argumentumnál kevesebbet ad meg, egy új függvényt hoz létre, amely a fennmaradó argumentumokat várja. Az argumentumok kezelésének ezt a módszerét nevezik curryingnek , és olyan funkcionális programozási nyelvek jellemzője, mint az F#. Tegyük fel például, hogy két csőmérettel dolgozik: az egyik sugara 2,0 , a másik sugara 3,0. Az alábbiak szerint hozhat létre olyan függvényeket, amelyek meghatározzák a cső térfogatát:

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

Ezután a két különböző méretű cső különböző hossza esetén szükség szerint adja meg a végső argumentumot:

let length1 = 30.0
let length2 = 40.0
let smallPipeVol1 = smallPipeVolume length1
let smallPipeVol2 = smallPipeVolume length2
let bigPipeVol1 = bigPipeVolume length1
let bigPipeVol2 = bigPipeVolume length2

Rekurzív függvények

A rekurzív függvények maguknak nevezett függvények. Ezek megkövetelik, hogy a let kulcsszót követően adja meg a rec kulcsszót. Hívja meg a rekurzív függvényt a függvény törzséből ugyanúgy, mint bármely függvényhívást. Az alábbi rekurzív függvény kiszámítja az n-edik Fibonacci-számot. A Fibonacci számsorozat már az ókor óta ismert, és olyan sorozat, amelyben minden egymást követő szám a sorozat előző két számának összege.

let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)

Egyes rekurzív függvények túlcsordulhatnak a programveremen, vagy nem hatékonyak, ha nem körültekintően és speciális technikákkal, például a farokrekurzió, az akkumulátorok és a folytatások használatával írják őket.

Függvényértékek

Az F#-ban minden függvény értéknek számít; valójában függvényértékekként ismertek. Mivel a függvények értékek, más függvények argumentumaként vagy más olyan környezetekben is használhatók, ahol értékeket használnak. Az alábbiakban egy példa látható egy függvényre, amely argumentumként vesz fel egy függvényértéket:

let apply1 (transform : int -> int ) y = transform y

A függvényérték típusát a -> jogkivonat használatával adhatja meg. A jogkivonat bal oldalán található az argumentum típusa, a jobb oldalon pedig a visszatérési érték. Az előző példában egy függvény argumentumként apply1 vesz fel egy függvényt transform , ahol transform egy függvény egy egész számot vesz fel, és egy másik egész számot ad vissza. A következő kód bemutatja, hogyan használható apply1:

let increment x = x + 1

let result1 = apply1 increment 100

Az érték result 101 lesz az előző kód futtatása után.

Több argumentumot egymást követő -> tokenek választanak el egymástól, ahogy az alábbi példában látható:

let apply2 ( f: int -> int -> int) x y = f x y

let mul x y = x * y

let result2 = apply2 mul 10 20

Az eredmény 200.

Lambda-kifejezések

A lambda kifejezés egy névtelen függvény. Az előző példákban a nevesített függvények növekményének és mul értékének meghatározása helyett a lambda kifejezéseket használhatja az alábbiak szerint:

let result3 = apply1 (fun x -> x + 1) 100

let result4 = apply2 (fun x y -> x * y ) 10 20

A lambda kifejezéseket a fun kulcsszó használatával definiálhatja. A lambda kifejezés hasonlít egy függvénydefinícióra, azzal a kivételrel, hogy a = jogkivonat helyett a -> jogkivonat választja el az argumentumlistát a függvény törzsétől. A normál függvénydefiníciókhoz hasonlóan az argumentumtípusok is kikövetkeztethetők vagy explicit módon megadhatók, a lambda kifejezés visszatérési típusa pedig a törzs utolsó kifejezésének típusából származik. További információ: Lambda-kifejezések: A fun kulcsszó.

Pipelines

A csőkezelőt |> széles körben használják az F#-adatok feldolgozásakor. Ez az operátor lehetővé teszi a függvények "folyamatainak" rugalmas létrehozását. A pipelining lehetővé teszi a függvényhívások egymást követő műveletekként való összekapcsolását:

let result = 100 |> function1 |> function2

Az alábbi minta bemutatja, hogyan hozhat létre egy egyszerű funkcionális folyamatot az operátorok használatával:


/// 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

Az eredmény : [2; 10; 26]. Az előző minta listafeldolgozó függvényeket használ, amelyek bemutatják, hogyan használhatók a függvények az adatok feldolgozására folyamatok létrehozásakor. Maga a folyamatoperátor az F#-magtárban van definiálva az alábbiak szerint:

let (|>) x f = f x

Függvényösszetétel

Az F# függvényei más függvényekből is összeállíthatók. Két függvényfüggvény1 és függvény2 összetétele egy másik függvény, amely a függvény1 alkalmazását, majd a függvény2 alkalmazását jelöli:

let function1 x = x + 1
let function2 x = x * 2
let h = function1 >> function2
let result5 = h 100

Az eredmény 202.

Az összeállítási operátor >> két függvényt vesz fel, és egy függvényt ad vissza. Ezzel szemben a folyamatoperátor |> egy értéket és egy függvényt vesz fel, és egy értéket ad vissza. Az alábbi példakód a folyamat és az összeállítási operátorok közötti különbséget mutatja be a függvényaláírások és a használat különbségeinek szemléltetésével.

// 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

Túlterhelési függvények

A metódusok túlterhelhetők, de függvények nem. További információ: Metódusok.

Lásd még