Použití funkcí v jazyce F#

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.

Definující charakteristikou jazyka F# je, že funkce mají stav první třídy. S funkcí můžete dělat cokoli, co můžete dělat s hodnotami ostatních předdefinovaných typů, se srovnatelným stupněm úsilí.

  • Můžete zadat názvy hodnot funkcí.

  • Funkce můžete ukládat do datových struktur, jako je seznam.

  • Funkci můžete předat jako argument ve volání funkce.

  • Funkci můžete vrátit z volání funkce.

Přiřazení názvu hodnotě

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 funkčním programování odkazováno jako na vázání identifikátoru na hodnotu. Jazyk F# používá let vazby k vytvoření vazby názvů na hodnoty: 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 pojmenovanou squareIt vazbou identifikátoru squareItna výrazfun n -> n * n lambda. 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 řazených kolekcích členů.

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

Za účelem ověření, že název funkce uložený v řazené kolekci členů povede ve skutečnosti k vyhodnocení funkce, používá následující příklad operátory fst a snd pro získání prvního a druhého prvku z řazené kolekce členů funAndArgTuple. První prvek v řazené kolekci členů je squareIt a druhý prvek je 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 použije první prvek v řazené kolekci členů na druhý prvek řazené kolekce členů: 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 identifikátor squareIt s výrazem lambda fun n -> n * n.

// Make a tuple 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 argumentu

Pokud hodnota patří k hodnotám stavu 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íte být schopni je stejným způsobem předat 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 parametru op předáte funkci, která má jeden parametr, a odpovídající argument funkce předáte do parametru arg, funkce vrátí výsledek použití parametru op do parametru arg. V následujícím příkladu jsou oba argumenty – argument funkce a argument celého čísla – odeslány stejným způsobem, a to 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 funkčních programovacích jazycích, jako jsou například operace mapování nebo filtrování. Například operace mapování je funkce vyššího řádu, která zachytává výpočet sdílený funkcemi, jež prochází seznamem, u každého prvku provedou 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ý 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. Tato část je zachycena ve funkci mapování. Jediné, co je třeba napsat pro konkrétní aplikaci, je funkce, kterou chcete použít na každý jednotlivý prvek seznamu (sčítání, umocňování, změna velikosti písmen). Tato funkce je předána jako argument funkci mapování, stejně jako je v předchozím příkladu prvek squareIt předán do funkce applyIt.

Jazyk F# poskytuje mapové metody pro většinu typů kolekcí, včetně seznamů, polí a sekvencí. 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.

Vrácení hodnoty z volání funkce

Pokud je funkce v jazyce ve stavu hodnoty první kategorie, musí být možné ji vrátit 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 vrací ř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, vrací 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áno 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 item vyhledá prvek lst. Pokud je prvek item nalezen, funkce vrací hodnotu true. Pokud není prvek item nalezen, funkce vrací hodnotu false. Stejně jako v předchozí části používá následující kód k prohledávání seznamu zadanou funkci 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á vrací 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 expression 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 skládající funkce, << a >>. Například let squareAndDouble2 = doubleIt << squareIt je ekvivalentní zápisu let squareAndDouble = compose doubleIt squareIt z předchozího příkladu.

Následující příklad vrácení funkce jako hodnoty volání funkce vytvoří jednoduchou hádací 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ý výraz lambda. Proto funkce playGame přijímá jako svůj argument hodnotu funkce 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!

Curryfikované funkce

Mnoho příkladů v předchozí části lze napsat výstižněji tím, že využijete implicitní kariing v deklarací funkcí jazyka F#. Curryfikace je proces, jenž 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, jež 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émkoli příkladě 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 pracuje 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:

Curryfikaci lze omezit uzavřením parametrů do řazených kolekcí členů. Další informace naleznete v části Vzory parametrů v parametrech a argumentech.

Následující příklad používá implicitní curryfikaci 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 pomocí původních testovacích případů lze ověřit, že je výsledek 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 currying naleznete v části Částečné použití argumentů ve funkcích.

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 proměnná 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 výraz lambda, se kterým je funkce svázána.

Následující příklad definuje funkci Boolean s názvem isNegative, poté použije název funkce a následně místo něj použije její definici. Všechny tři následující příklady vracejí hodnotu False a zobrazují 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 hodnoty první třídy v jazyce F.#

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# najdete v referenční dokumentaci jazyka F#.

Příklad

Popis

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

Kó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 expression 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é