Sdílet prostřednictvím


Funkce jako prvotřídní hodnoty (F#)

Charakteristickým znakem funkcionálních programovacích jazyků je povýšení funkcí do stavu první kategorie.Měli by jste být schopni provádět s funkcí to, co můžete provádět s hodnotami ostatních předdefinovaných typů a být schopni tak činit se srovnatelnou mírou úsilí.

Typická opatření stavu první kategorie zahrnují:

  • Lze vázat identifikátor na hodnotu?Znamená to, že jí lze přiřadit název?

  • Lze uložit hodnotu do datové struktury, například seznamu?

  • Lze předat hodnotu jako argument ve volání funkce?

  • Lze vrátit hodnotu jako hodnotu volání funkce?

Poslední dvě opatření definují to, co je známo jako operace vyššího řádu či funkce vyššího řádu.Funkce vyššího řádu přijímají funkce jako argumenty a funkce vrací jako hodnotu volání funkce.Tyto operace podporují stěžejní části funkcionálního programování jako funkce mapování a skládání funkcí.

Dává hodnotě název

Pokud je funkce hodnotou první kategorie, je třeba ji pojmenovat, stejně jako lze pojmenovat celá čísla, řetězce a další předdefinované typy.Na to je podle literatury o funkcionálním programování odkazováno jako na vázání identifikátoru na hodnotu.Jazyk F# používá pro svázání názvů a hodnot výrazy let: let <identifier> = <value>.Následující kód ukazuje dva příklady.

// Integer and string.
let num = 10
let str = "F#"

Funkci lze pojmenovat stejně snadno.Následující příklad definuje funkci nazvanou squareIt svázáním identifikátoru squareIt s lambda výrazemfun n -> n * n.Funkce squareIt má jeden parametr n a vrací druhou mocninu tohoto parametru.

let squareIt = fun n -> n * n

Jazyk F# poskytuje pro dosažení stejného výsledku s kratším zápisem následující stručnější syntaxi.

let squareIt2 n = n * n

Následující příklady používají pro zvýraznění podobností mezi deklaracemi funkcí a deklaracemi dalších typů hodnot převážně první styl, let <function-name> = <lambda-expression>.Všechny pojmenované funkce lze ale také zapsat pomocí stručnější syntaxe.Některé příklady jsou zapsány oběma způsoby.

Uložení hodnoty do datové struktury

Hodnota první kategorie může být uložena v datové struktuře.Následující kód ukazuje příklady, které ukládají hodnoty v seznamech a n-ticích.

// Lists.

// Storing integers and strings.
let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
let stringList = [ "one"; "two"; "three" ]

// You cannot mix types in a list. The following declaration causes a 
// type-mismatch compiler error.
//let failedList = [ 5; "six" ]

// In F#, functions can be stored in a list, as long as the functions 
// have the same signature.

// Function doubleIt has the same signature as squareIt, declared previously.
//let squareIt = fun n -> n * n
let doubleIt = fun n -> 2 * n

// Functions squareIt and doubleIt can be stored together in a list.
let funList = [ squareIt; doubleIt ]

// Function squareIt cannot be stored in a list together with a function
// that has a different signature, such as the following body mass 
// index (BMI) calculator.
let BMICalculator = fun ht wt -> 
                    (float wt / float (squareIt ht)) * 703.0

// The following expression causes a type-mismatch compiler error.
//let failedFunList = [ squareIt; BMICalculator ]


// Tuples.

// Integers and strings.
let integerTuple = ( 1, -7 )
let stringTuple = ( "one", "two", "three" )

// A tuple does not require its elements to be of the same type.
let mixedTuple = ( 1, "two", 3.3 )

// Similarly, function elements in tuples can have different signatures.
let funTuple = ( squareIt, BMICalculator )

// Functions can be mixed with integers, strings, and other types in
// a tuple. Identifier num was declared previously.
//let num = 10
let moreMixedTuple = ( num, "two", 3.3, squareIt )

Pro ověření, že název funkce, uložený v n-tici povede ve skutečnosti k vyhodnocení funkce, používá následující příklad pro získání prvního a druhého prvku z n-tice funAndArgTuple operátory fst a snd.První prvek v n-tici je squareIt a druhý prvek num.Identifikátor num je v předchozím příkladu svázán s celým číslem 10, platným argumentem pro funkci squareIt.Druhý výraz aplikuje první prvek v n-tici na druhý prvek n-tice: squareIt num.

// You can pull a function out of a tuple and apply it. Both squareIt and num
// were defined previously.
let funAndArgTuple = (squareIt, num)

// The following expression applies squareIt to num, returns 100, and 
// then displays 100.
System.Console.WriteLine((fst funAndArgTuple)(snd funAndArgTuple))

Podobně jako lze identifikátor num zaměnit s celým číslem 10, lze zaměnit squareIt s lambda výrazem fun n -> n * n.

// Make a list of values instead of identifiers.
let funAndArgTuple2 = ((fun n -> n * n), 10)

// The following expression applies a squaring function to 10, returns
// 100, and then displays 100.
System.Console.WriteLine((fst funAndArgTuple2)(snd funAndArgTuple2))

Předání hodnoty jako argument

Pokud patří hodnota k hodnotám první kategorie jazyka, lze ji předat jako argument funkce.Je například běžné předávat jako argumenty celá čísla a řetězce.Následující kód ukazuje předání celých čísel a řetězců jako argumentů v jazyce F#.

// An integer is passed to squareIt. Both squareIt and num are defined in 
// previous examples.
//let num = 10
//let squareIt = fun n -> n * n
System.Console.WriteLine(squareIt num)

// String.
// Function repeatString concatenates a string with itself.
let repeatString = fun s -> s + s

// A string is passed to repeatString. HelloHello is returned and displayed.
let greeting = "Hello"
System.Console.WriteLine(repeatString greeting)

Pokud jsou funkce ve stavu hodnoty první kategorie, musí být schopna být předána stejným způsobem jako argumenty.Zapamatujte si, že se jedná o první charakteristiku funkcí vyššího řádu.

V následujícím příkladu má funkce applyIt dva parametry, op a arg.Pokud do op předáte funkci, která má jeden parametr, a odpovídající argument funkce do arg, funkce vrátí výsledek aplikace op na arg.V následujícím příkladu jsou oba argumenty, argument funkce a argument celého čísla odeslány stejným způsobem, použitím jejich názvů.

// Define the function, again using lambda expression syntax.
let applyIt = fun op arg -> op arg

// Send squareIt for the function, op, and num for the argument you want to 
// apply squareIt to, arg. Both squareIt and num are defined in previous 
// examples. The result returned and displayed is 100.
System.Console.WriteLine(applyIt squareIt num)

// The following expression shows the concise syntax for the previous function
// definition.
let applyIt2 op arg = op arg
// The following line also displays 100.
System.Console.WriteLine(applyIt2 squareIt num)

Možnost odeslat funkci jako argument do jiné funkce je základem společných abstrakcí ve funkcionálních programovacích jazycích, jako například operace map nebo filter.Například operace map je funkce vyššího řádu, která zachytává výpočet, sdílený funkcemi, který prochází seznamem, u každého elementu provede nějakou operaci a poté vrátí seznam výsledků.Může být například třeba zvýšit každý prvek v seznamu celých čísel o jedna, každý jeho prvek umocnit na druhou, nebo převést každý prvek seznamu řetězců na velká písmena.Rekurzivní proces, který prochází seznam a vytváří seznam výsledků k vrácení, je část výpočtu náchylná k chybám.Část je zachycena ve funkci mapování.Jediné, co je třeba napsat pro konkrétní aplikaci je funkce, kterou je třeba provést nad každým jednotlivým prvkem seznamu (sčítání, umocňování, změna velikosti písmen).Tato funkce je předána jako argument funkci map, stejně jako je v předchozím příkladu squareIt předán do applyIt.

Jazyk F# poskytuje metody map pro většinu typů kolekcí, včetně seznamu, pole a množin.Následující příklady používají seznamy.Syntaxe je List.map <the function> <the list>.

// List integerList was defined previously:
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]

// You can send the function argument by name, if an appropriate function
// is available. The following expression uses squareIt.
let squareAll = List.map squareIt integerList

// The following line displays [1; 4; 9; 16; 25; 36; 49]
printfn "%A" squareAll

// Or you can define the action to apply to each list element inline.
// For example, no function that tests for even integers has been defined,
// so the following expression defines the appropriate function inline.
// The function returns true if n is even; otherwise it returns false.
let evenOrNot = List.map (fun n -> n % 2 = 0) integerList

// The following line displays [false; true; false; true; false; true; false]
printfn "%A" evenOrNot

Další informace naleznete v tématu Seznamy (F#).

Vrácení hodnoty z volání funkce

Pokud je funkce v jazyce ve stavu hodnoty první kategorie, musíte být schopni vrátit ji jako hodnotu volání funkce, stejně tak jako jsou vraceny další typy, jako například celá čísla a řetězce.

Následující volání funkce vrací celá čísla a zobrazí je.

// Function doubleIt is defined in a previous example.
//let doubleIt = fun n -> 2 * n
System.Console.WriteLine(doubleIt 3)
System.Console.WriteLine(squareIt 4)

Následující volání funkce vrátí řetězec.

// str is defined in a previous section.
//let str = "F#"
let lowercase = str.ToLower()

Následující volání funkce, deklarované na jednom řádku, vrátí logickou hodnotu.Zobrazená hodnota je True.

System.Console.WriteLine((fun n -> n % 2 = 1) 15)

Schopnost vracet funkci jako hodnotu volání funkce je druhým charakteristickým znakem funkcí vyššího řádu.V následujícím příkladu je checkFor definována jako funkce, která převezme jeden argument item a jako hodnotu vrátí novou funkci.Vrácená funkce převezme seznam jako argument lst a v argumentu lst vyhledá prvek item.Pokud je prvek item nalezen, funkce vrátí hodnotu true.Pokud není item nalezen, funkce vrátí false.Stejně jako v předchozí části používá následující kód pro prohledání seznamu poskytnutou funkci seznamu List.exists.

let checkFor item = 
    let functionToReturn = fun lst ->
                           List.exists (fun a -> a = item) lst
    functionToReturn

Následující kód používá pro vytvoření nové funkce funkci checkFor, která přijímá jeden argument, seznam, a vyhledá v něm číslo 7.

// integerList and stringList were defined earlier.
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
//let stringList = [ "one"; "two"; "three" ]

// The returned function is given the name checkFor7. 
let checkFor7 = checkFor 7

// The result displayed when checkFor7 is applied to integerList is True.
System.Console.WriteLine(checkFor7 integerList)

// The following code repeats the process for "seven" in stringList.
let checkForSeven = checkFor "seven"

// The result displayed is False.
System.Console.WriteLine(checkForSeven stringList)

Následující příklad používá pro deklaraci funkce compose, která vrátí složení dvou argumentů funkce, stav první kategorie funkcí jazyka F#.

// Function compose takes two arguments. Each argument is a function 
// that takes one argument of the same type. The following declaration
// uses lambda expresson syntax.
let compose = 
    fun op1 op2 ->
        fun n ->
            op1 (op2 n)

// To clarify what you are returning, use a nested let expression:
let compose2 = 
    fun op1 op2 ->
        // Use a let expression to build the function that will be returned.
        let funToReturn = fun n ->
                            op1 (op2 n)
        // Then just return it.
        funToReturn

// Or, integrating the more concise syntax:
let compose3 op1 op2 =
    let funToReturn = fun n ->
                        op1 (op2 n)
    funToReturn

[!POZNÁMKA]

Ještě kratší verzi naleznete v následující části "Curryfikované funkce".

Následující kód předá funkci compose dvě funkce jako argumenty, obě přijímající jediný argument stejného typu.Vrácená hodnota je nová funkce, která je složením obou argumentů funkce.

// Functions squareIt and doubleIt were defined in a previous example.
let doubleAndSquare = compose squareIt doubleIt
// The following expression doubles 3, squares 6, and returns and
// displays 36.
System.Console.WriteLine(doubleAndSquare 3)

let squareAndDouble = compose doubleIt squareIt
// The following expression squares 3, doubles 9, returns 18, and
// then displays 18.
System.Console.WriteLine(squareAndDouble 3)

[!POZNÁMKA]

Jazyk F# obsahuje dva operátory které skládají funkce, << a >>.Například let squareAndDouble2 = doubleIt << squareIt je ekvivalentní let squareAndDouble = compose doubleIt squareIt z předchozího příkladu.

Následující příklad vracení funkce jako hodnoty volání funkce vytvoří jednoduchou hádající hru.Pro tvorbu hry je třeba zavolat funkci makeGame s hodnotou, kterou má někdo uhodnout, předanou do argumentu target.Vrácená hodnota z funkce makeGame je funkce, která přijímá jeden argument (odhad) a hlásí, zda je odhad správný.

let makeGame target = 
    // Build a lambda expression that is the function that plays the game.
    let game = fun guess -> 
                   if guess = target then
                      System.Console.WriteLine("You win!")
                   else 
                      System.Console.WriteLine("Wrong. Try again.")
    // Now just return it.
    game

Následující kód volá funkci makeGame, předávající hodnotu 7 do argumentu target.Identifikátor playGame je vázán na vrácený lambda výraz.Proto funkce playGame přijímá jako svůj argument hodnotu pro guess.

let playGame = makeGame 7
// Send in some guesses.
playGame 2
playGame 9
playGame 7

// Output:
// Wrong. Try again.
// Wrong. Try again.
// You win!

// The following game specifies a character instead of an integer for target. 
let alphaGame = makeGame 'q'
alphaGame 'c'
alphaGame 'r'
alphaGame 'j'
alphaGame 'q'

// Output:
// Wrong. Try again.
// Wrong. Try again.
// Wrong. Try again.
// You win!

Curried funkce

Mnoho příkladů z předchozí části lze s využitím implicitního procesu currying v deklaracích funkcí jazyka F# zapsat výstižněji.Currying je proces, který transformuje funkci, která má více než jeden parametr do řady vložených funkcí, z nichž každá má jeden parametr.V jazyce F# jsou funkce, které mají více než jeden parametr, ze své podstaty curryfikovány.Například funkci compose z předchozí části lze zapsat pomocí následujícího stručného stylu se třemi parametry.

let compose4 op1 op2 n = op1 (op2 n)

Výsledkem je ale funkce jednoho parametru, která vrací funkci jednoho parametru, která zase vrací jinou funkci jednoho parametru, tak jak je vidět ve funkci compose4curried.

let compose4curried =
    fun op1 ->
        fun op2 ->
            fun n -> op1 (op2 n)

K této funkci lze přistupovat několika způsoby.Každý z následujících příkladů vrátí a zobrazí číslo 18.Funkci compose4 lze v jakémkoliv příkladu nahradit funkcí compose4curried.

// Access one layer at a time.
System.Console.WriteLine(((compose4 doubleIt) squareIt) 3)

// Access as in the original compose examples, sending arguments for 
// op1 and op2, then applying the resulting function to a value.
System.Console.WriteLine((compose4 doubleIt squareIt) 3)

// Access by sending all three arguments at the same time.
System.Console.WriteLine(compose4 doubleIt squareIt 3)

Pro ověření, zda funkce stále funguje stejně jako dříve, lze opětovně vyzkoušet původní testovací případy.

let doubleAndSquare4 = compose4 squareIt doubleIt
// The following expression returns and displays 36.
System.Console.WriteLine(doubleAndSquare4 3)

let squareAndDouble4 = compose4 doubleIt squareIt
// The following expression returns and displays 18.
System.Console.WriteLine(squareAndDouble4 3)

[!POZNÁMKA]

Currying lze omezit uzavřením parametrů do n-tic.Další informace naleznete v části "Vzory parametrů" v tématu Parametry a argumenty (F#).

Následující příklad používá implicitní currying pro zápis kratší verze funkce makeGame.Podrobné informace o tom jak funkce makeGame konstruuje a vrací funkci game jsou v tomto formátu méně explicitní, ale lze je ověřit pomocí původních testovacích případů, jejichž výsledek je stejný.

let makeGame2 target guess =
    if guess = target then
       System.Console.WriteLine("You win!")
    else 
       System.Console.WriteLine("Wrong. Try again.")

let playGame2 = makeGame2 7
playGame2 2
playGame2 9
playGame2 7

let alphaGame2 = makeGame2 'q'
alphaGame2 'c'
alphaGame2 'r'
alphaGame2 'j'
alphaGame2 'q'

Další informace o procesu currying naleznete v části "Částečná aplikace argumentů" v tématu Funkce (F#).

Definice identifikátoru a funkce jsou zaměnitelné

Název proměnné num je v předchozích příkladech vyhodnocen jako celé číslo 10 a není žádným překvapením, že pokud je num platný, číslo 10 je také platné.Totéž platí i pro identifikátory funkcí a jejich hodnoty: kdekoli lze použít název funkce, lze také použít lambda výraz, se kterým je funkce svázána.

Následující příklad definuje funkci, vracející hodnotu Boolean, nazvanou isNegative, poté použije její název funkce a poté místo něj použije její definici.Všechny následující tři příklady vracejí hodnotu False a zobrazí ji.

let isNegative = fun n -> n < 0

// This example uses the names of the function argument and the integer
// argument. Identifier num is defined in a previous example.
//let num = 10
System.Console.WriteLine(applyIt isNegative num)

// This example substitutes the value that num is bound to for num, and the
// value that isNegative is bound to for isNegative.
System.Console.WriteLine(applyIt (fun n -> n < 0) 10) 

Pro provedení dalšího kroku nahraďte hodnotu, ke které je svázán identifikátor applyIt, hodnotou applyIt.

System.Console.WriteLine((fun op arg -> op arg) (fun n -> n < 0)  10)

Funkce jsou v jazyce F# hodnotami první kategorie

Příklady v předchozích částech ukazují, že funkce jazyka F# splňují kritéria pro hodnoty první kategorie:

  • Identifikátor lze svázat s definicí funkce.

    let squareIt = fun n -> n * n
    
  • Funkci lze uložit v datové struktuře.

    let funTuple2 = ( BMICalculator, fun n -> n * n )
    
  • Funkci lze předat jako argument.

    let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]
    
  • Funkci lze vrátit jako hodnotu volání funkce.

    let checkFor item = 
        let functionToReturn = fun lst ->
                               List.exists (fun a -> a = item) lst
        functionToReturn
    

Další informace o jazyce F# viz Co je nového pro Visual F# v roce 2012 Visual Studio nebo F# Language Reference.

Příklad

Dd233158.collapse_all(cs-cz,VS.110).gifDescription

Následující kód obsahuje všechny příklady tohoto tématu.

Dd233158.collapse_all(cs-cz,VS.110).gifKód


// ** GIVE THE VALUE A NAME **

// Integer and string.
let num = 10
let str = "F#"

let squareIt = fun n -> n * n

let squareIt2 n = n * n


// ** STORE THE VALUE IN A DATA STRUCTURE **

// Lists.

// Storing integers and strings.
let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
let stringList = [ "one"; "two"; "three" ]

// You cannot mix types in a list. The following declaration causes a 
// type-mismatch compiler error.
//let failedList = [ 5; "six" ]

// In F#, functions can be stored in a list, as long as the functions 
// have the same signature.

// Function doubleIt has the same signature as squareIt, declared previously.
//let squareIt = fun n -> n * n
let doubleIt = fun n -> 2 * n

// Functions squareIt and doubleIt can be stored together in a list.
let funList = [ squareIt; doubleIt ]

// Function squareIt cannot be stored in a list together with a function
// that has a different signature, such as the following body mass 
// index (BMI) calculator.
let BMICalculator = fun ht wt -> 
                    (float wt / float (squareIt ht)) * 703.0

// The following expression causes a type-mismatch compiler error.
//let failedFunList = [ squareIt; BMICalculator ]


// Tuples.

// Integers and strings.
let integerTuple = ( 1, -7 )
let stringTuple = ( "one", "two", "three" )

// A tuple does not require its elements to be of the same type.
let mixedTuple = ( 1, "two", 3.3 )

// Similarly, function elements in tuples can have different signatures.
let funTuple = ( squareIt, BMICalculator )

// Functions can be mixed with integers, strings, and other types in
// a tuple. Identifier num was declared previously.
//let num = 10
let moreMixedTuple = ( num, "two", 3.3, squareIt )

// You can pull a function out of a tuple and apply it. Both squareIt and num
// were defined previously.
let funAndArgTuple = (squareIt, num)

// The following expression applies squareIt to num, returns 100, and 
// then displays 100.
System.Console.WriteLine((fst funAndArgTuple)(snd funAndArgTuple))

// Make a list of values instead of identifiers.
let funAndArgTuple2 = ((fun n -> n * n), 10)

// The following expression applies a squaring function to 10, returns
// 100, and then displays 100.
System.Console.WriteLine((fst funAndArgTuple2)(snd funAndArgTuple2))


// ** PASS THE VALUE AS AN ARGUMENT **

// An integer is passed to squareIt. Both squareIt and num are defined in 
// previous examples.
//let num = 10
//let squareIt = fun n -> n * n
System.Console.WriteLine(squareIt num)

// String.
// Function repeatString concatenates a string with itself.
let repeatString = fun s -> s + s

// A string is passed to repeatString. HelloHello is returned and displayed.
let greeting = "Hello"
System.Console.WriteLine(repeatString greeting)

// Define the function, again using lambda expression syntax.
let applyIt = fun op arg -> op arg

// Send squareIt for the function, op, and num for the argument you want to 
// apply squareIt to, arg. Both squareIt and num are defined in previous 
// examples. The result returned and displayed is 100.
System.Console.WriteLine(applyIt squareIt num)

// The following expression shows the concise syntax for the previous function
// definition.
let applyIt2 op arg = op arg
// The following line also displays 100.
System.Console.WriteLine(applyIt2 squareIt num)

// List integerList was defined previously:
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]

// You can send the function argument by name, if an appropriate function
// is available. The following expression uses squareIt.
let squareAll = List.map squareIt integerList

// The following line displays [1; 4; 9; 16; 25; 36; 49]
printfn "%A" squareAll

// Or you can define the action to apply to each list element inline.
// For example, no function that tests for even integers has been defined,
// so the following expression defines the appropriate function inline.
// The function returns true if n is even; otherwise it returns false.
let evenOrNot = List.map (fun n -> n % 2 = 0) integerList

// The following line displays [false; true; false; true; false; true; false]
printfn "%A" evenOrNot


// ** RETURN THE VALUE FROM A FUNCTION CALL **

// Function doubleIt is defined in a previous example.
//let doubleIt = fun n -> 2 * n
System.Console.WriteLine(doubleIt 3)
System.Console.WriteLine(squareIt 4)

// The following function call returns a string:
// str is defined in a previous section.
//let str = "F#"
let lowercase = str.ToLower()

System.Console.WriteLine((fun n -> n % 2 = 1) 15)

let checkFor item = 
    let functionToReturn = fun lst ->
                           List.exists (fun a -> a = item) lst
    functionToReturn

// integerList and stringList were defined earlier.
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
//let stringList = [ "one"; "two"; "three" ]

// The returned function is given the name checkFor7. 
let checkFor7 = checkFor 7

// The result displayed when checkFor7 is applied to integerList is True.
System.Console.WriteLine(checkFor7 integerList)

// The following code repeats the process for "seven" in stringList.
let checkForSeven = checkFor "seven"

// The result displayed is False.
System.Console.WriteLine(checkForSeven stringList)

// Function compose takes two arguments. Each argument is a function 
// that takes one argument of the same type. The following declaration
// uses lambda expresson syntax.
let compose = 
    fun op1 op2 ->
        fun n ->
            op1 (op2 n)

// To clarify what you are returning, use a nested let expression:
let compose2 = 
    fun op1 op2 ->
        // Use a let expression to build the function that will be returned.
        let funToReturn = fun n ->
                            op1 (op2 n)
        // Then just return it.
        funToReturn

// Or, integrating the more concise syntax:
let compose3 op1 op2 =
    let funToReturn = fun n ->
                        op1 (op2 n)
    funToReturn

// Functions squareIt and doubleIt were defined in a previous example.
let doubleAndSquare = compose squareIt doubleIt
// The following expression doubles 3, squares 6, and returns and
// displays 36.
System.Console.WriteLine(doubleAndSquare 3)

let squareAndDouble = compose doubleIt squareIt
// The following expression squares 3, doubles 9, returns 18, and
// then displays 18.
System.Console.WriteLine(squareAndDouble 3)

let makeGame target = 
    // Build a lambda expression that is the function that plays the game.
    let game = fun guess -> 
                   if guess = target then
                      System.Console.WriteLine("You win!")
                   else 
                      System.Console.WriteLine("Wrong. Try again.")
    // Now just return it.
    game

let playGame = makeGame 7
// Send in some guesses.
playGame 2
playGame 9
playGame 7

// Output:
// Wrong. Try again.
// Wrong. Try again.
// You win!

// The following game specifies a character instead of an integer for target. 
let alphaGame = makeGame 'q'
alphaGame 'c'
alphaGame 'r'
alphaGame 'j'
alphaGame 'q'

// Output:
// Wrong. Try again.
// Wrong. Try again.
// Wrong. Try again.
// You win!


// ** CURRIED FUNCTIONS **

let compose4 op1 op2 n = op1 (op2 n)

let compose4curried =
    fun op1 ->
        fun op2 ->
            fun n -> op1 (op2 n)

// Access one layer at a time.
System.Console.WriteLine(((compose4 doubleIt) squareIt) 3)

// Access as in the original compose examples, sending arguments for 
// op1 and op2, then applying the resulting function to a value.
System.Console.WriteLine((compose4 doubleIt squareIt) 3)

// Access by sending all three arguments at the same time.
System.Console.WriteLine(compose4 doubleIt squareIt 3)

let doubleAndSquare4 = compose4 squareIt doubleIt
// The following expression returns and displays 36.
System.Console.WriteLine(doubleAndSquare4 3)

let squareAndDouble4 = compose4 doubleIt squareIt
// The following expression returns and displays 18.
System.Console.WriteLine(squareAndDouble4 3)

let makeGame2 target guess =
    if guess = target then
       System.Console.WriteLine("You win!")
    else 
       System.Console.WriteLine("Wrong. Try again.")

let playGame2 = makeGame2 7
playGame2 2
playGame2 9
playGame2 7

let alphaGame2 = makeGame2 'q'
alphaGame2 'c'
alphaGame2 'r'
alphaGame2 'j'
alphaGame2 'q'


// ** IDENTIFIER AND FUNCTION DEFINITION ARE INTERCHANGEABLE **

let isNegative = fun n -> n < 0

// This example uses the names of the function argument and the integer
// argument. Identifier num is defined in a previous example.
//let num = 10
System.Console.WriteLine(applyIt isNegative num)

// This example substitutes the value that num is bound to for num, and the
// value that isNegative is bound to for isNegative.
System.Console.WriteLine(applyIt (fun n -> n < 0) 10) 

System.Console.WriteLine((fun op arg -> op arg) (fun n -> n < 0)  10)


// ** FUNCTIONS ARE FIRST-CLASS VALUES IN F# **

//let squareIt = fun n -> n * n

let funTuple2 = ( BMICalculator, fun n -> n * n )

let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]

//let checkFor item = 
//    let functionToReturn = fun lst ->
//                           List.exists (fun a -> a = item) lst
//    functionToReturn

Viz také

Referenční dokumentace

N-tic (F#)

Funkce (F#)

Nechť vazby (F#)

Lambda výrazy: Fun klíčové slovo (F#)

Další zdroje

Seznamy (F#)