Uso delle funzioni in F#

Una definizione di funzione semplice è simile alla seguente:

let f x = x + 1

Nell'esempio precedente, il nome della funzione è f, l'argomento è x ed è di tipo int, il corpo della funzione è x + 1 e il valore restituito è di tipo int.

Una caratteristica che definisce F# è che le funzioni hanno uno stato di prima classe. È possibile eseguire operazioni con una funzione che è possibile eseguire con i valori degli altri tipi predefiniti, con un grado di sforzo paragonabile.

  • È possibile assegnare nomi di valori di funzione.

  • È possibile archiviare funzioni in strutture di dati, ad esempio in un elenco.

  • È possibile passare una funzione come argomento in una chiamata di funzione.

  • È possibile restituire una funzione da una chiamata di funzione.

Assegnare un nome al valore

Se una funzione è un valore di prima classe, è necessario essere in grado di denominarla, esattamente come è possibile denominare numeri interi, stringhe e altri tipi predefiniti. Questa operazione viene definita letteratura di programmazione funzionale come associazione di un identificatore a un valore. F# usa associazioni let per associare nomi a valori: let <identifier> = <value>. Il codice seguente illustra due esempi.

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

È possibile assegnare un nome semplice a una funzione. Nell'esempio seguente viene definita una funzione denominata squareIt associando l'identificatore squareIt all'espressione fun n -> n * nlambda. La funzione squareIt ha un parametro, ne restituisce il quadrato di tale parametro.

let squareIt = fun n -> n * n

F# fornisce la sintassi più concisa seguente per ottenere lo stesso risultato con meno tipizzazione.

let squareIt2 n = n * n

Gli esempi che seguono usano principalmente il primo stile, let <function-name> = <lambda-expression>, per evidenziare le analogie tra la dichiarazione di funzioni e la dichiarazione di altri tipi di valori. Tuttavia, tutte le funzioni denominate possono essere scritte anche con la sintassi concisa. Alcuni esempi sono scritti in entrambi i modi.

Archiviare il valore in una struttura di dati

Un valore di prima classe può essere archiviato in una struttura di dati. Il codice seguente mostra esempi che archivia i valori negli elenchi e nelle tuple.

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

Per verificare che un nome di funzione archiviato in una tupla restituisca effettivamente una funzione, nell'esempio seguente vengono usati gli fst operatori e snd per estrarre i primi e i secondi elementi dalla tupla funAndArgTuple. Il primo elemento nella tupla è squareIt e il secondo elemento è num. L'identificatore num è associato in un esempio precedente a integer 10, un argomento valido per la squareIt funzione. La seconda espressione applica il primo elemento della tupla al secondo elemento della tupla: 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))

Analogamente, è possibile usare in modo intercambiabile l'identificatore num e l'intero 10, in modo da poter identificatore squareIt ed espressione fun n -> n * nlambda .

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

Passare il valore come argomento

Se un valore ha uno stato di prima classe in una lingua, è possibile passarlo come argomento a una funzione. Ad esempio, è comune passare numeri interi e stringhe come argomenti. Il codice seguente mostra numeri interi e stringhe passati come argomenti in 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)

Se le funzioni hanno uno stato di prima classe, è necessario essere in grado di passarle come argomenti nello stesso modo. Tenere presente che questa è la prima caratteristica delle funzioni di ordine superiore.

Nell'esempio seguente, la funzione applyIt ha due parametri e oparg. Se si invia in una funzione con un parametro per op e un argomento appropriato per la funzione a arg, la funzione restituisce op il risultato dell'applicazione a arg. Nell'esempio seguente, sia l'argomento della funzione che l'argomento integer vengono inviati nello stesso modo usando i relativi nomi.

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

La possibilità di inviare una funzione come argomento a un'altra funzione sottoscriva astrazioni comuni nei linguaggi di programmazione funzionale, ad esempio le operazioni di mapping o filtro. Un'operazione di mapping, ad esempio, è una funzione di ordine superiore che acquisisce il calcolo condiviso dalle funzioni che eseguono un elenco, eseguono un'operazione a ogni elemento e quindi restituiscono un elenco dei risultati. È possibile incrementare ogni elemento in un elenco di numeri interi o al quadrato di ogni elemento oppure modificare ogni elemento in un elenco di stringhe in lettere maiuscole. La parte soggetta a errori del calcolo è il processo ricorsivo che esegue la procedura nell'elenco e compila un elenco dei risultati da restituire. Tale parte viene acquisita nella funzione di mapping. Tutto quello che devi scrivere per una particolare applicazione è la funzione che vuoi applicare a ogni elemento elenco singolarmente (aggiunta, quaring, modifica di maiuscole e minuscole). Tale funzione viene inviata come argomento alla funzione di mapping, così come squareIt viene inviata a applyIt nell'esempio precedente.

F# fornisce metodi di mapping per la maggior parte dei tipi di raccolta, inclusi elenchi, matrici e sequenze. Negli esempi seguenti vengono usati elenchi. La sintassi è 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

Per altre informazioni, vedere Elenchi.

Restituire il valore da una chiamata di funzione

Infine, se una funzione ha lo stato di prima classe in un linguaggio, è necessario essere in grado di restituirla come valore di una chiamata di funzione, proprio come si restituiscono altri tipi, ad esempio numeri interi e stringhe.

La funzione seguente chiama i numeri interi restituiti e li visualizza.

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

La chiamata di funzione seguente restituisce una stringa.

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

La chiamata di funzione seguente, dichiarata inline, restituisce un valore booleano. Il valore visualizzato è True.

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

La possibilità di restituire una funzione come valore di una chiamata di funzione è la seconda caratteristica delle funzioni di ordine superiore. Nell'esempio checkFor seguente viene definito come una funzione che accetta un argomento, iteme restituisce una nuova funzione come valore. La funzione restituita accetta un elenco come argomento, lste cerca item in lst. Se item è presente, la funzione restituisce true. Se item non è presente, la funzione restituisce false. Come nella sezione precedente, il codice seguente usa una funzione elenco fornita, List.exists, per eseguire ricerche nell'elenco.

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

Il codice seguente usa checkFor per creare una nuova funzione che accetta un argomento, un elenco e cerca 7 nell'elenco.

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

Nell'esempio seguente viene usato lo stato di prima classe delle funzioni in F# per dichiarare una funzione, compose, che restituisce una composizione di due argomenti di funzione.

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

Nota

Per una versione ancora più breve, vedere la sezione seguente" "Funzioni curried".

Il codice seguente invia due funzioni come argomenti a compose, entrambi accettano un singolo argomento dello stesso tipo. Il valore restituito è una nuova funzione che rappresenta una composizione dei due argomenti della funzione.

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

Nota

F# fornisce due operatori, << e >>, che compongono funzioni. Ad esempio, let squareAndDouble2 = doubleIt << squareIt equivale a let squareAndDouble = compose doubleIt squareIt nell'esempio precedente.

L'esempio seguente di restituzione di una funzione come valore di una chiamata di funzione crea un semplice gioco di ipotesi. Per creare un gioco, chiamare makeGame con il valore che si vuole che qualcuno indovina inviato per target. Il valore restituito dalla funzione makeGame è una funzione che accetta un argomento (ipotesi) e segnala se l'ipotesi è corretta.

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

Il codice seguente chiama makeGame, inviando il valore 7 per target. L'identificatore playGame è associato all'espressione lambda restituita. Di conseguenza, playGame è una funzione che accetta come argomento un valore per 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!

Funzioni curried

Molti degli esempi nella sezione precedente possono essere scritti in modo più conciso sfruttando il currying implicito nelle dichiarazioni di funzione F#. Currying è un processo che trasforma una funzione con più di un parametro in una serie di funzioni incorporate, ognuna delle quali ha un singolo parametro. In F# le funzioni con più di un parametro sono intrinsecamente curried. Ad esempio, compose dalla sezione precedente è possibile scrivere come illustrato nello stile conciso seguente, con tre parametri.

let compose4 op1 op2 n = op1 (op2 n)

Tuttavia, il risultato è una funzione di un parametro che restituisce una funzione di un parametro che a sua volta restituisce un'altra funzione di un parametro, come illustrato in compose4curried.

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

È possibile accedere a questa funzione in diversi modi. Ognuno degli esempi seguenti restituisce e visualizza 18. È possibile sostituire compose4 con compose4curried in uno degli esempi.

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

Per verificare che la funzione funzioni ancora come in precedenza, provare di nuovo i test case originali.

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)

Nota

È possibile limitare il curry racchiudendo i parametri nelle tuple. Per altre informazioni, vedere "Modelli di parametri" in Parametri e argomenti.

Nell'esempio seguente viene usato il currying implicito per scrivere una versione più breve di makeGame. I dettagli sul modo makeGame in cui costrutti e restituisce la game funzione sono meno espliciti in questo formato, ma è possibile verificare usando i test case originali che il risultato è lo stesso.

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'

Per altre informazioni sul currying, vedere "Applicazione parziale degli argomenti" in Funzioni.

Identificatore e definizione di funzione sono intercambiabili

Il nome num della variabile negli esempi precedenti restituisce l'intero 10 e non sorprende che num dove sia valido, anche 10 è valido. Lo stesso vale per gli identificatori di funzione e i relativi valori: ovunque sia possibile usare il nome della funzione, l'espressione lambda a cui è associato può essere usata.

L'esempio seguente definisce una Boolean funzione denominata isNegativee quindi usa il nome della funzione e la definizione della funzione in modo intercambiabile. I tre esempi successivi restituiscono e visualizzano False.

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)

Per eseguire un ulteriore passaggio, sostituire il valore applyIt associato a per applyIt.

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

Le funzioni sono valori di prima classe in F#

Gli esempi nelle sezioni precedenti illustrano che le funzioni in F# soddisfano i criteri per essere valori di prima classe in F#:

  • È possibile associare un identificatore a una definizione di funzione.
let squareIt = fun n -> n * n
  • È possibile archiviare una funzione in una struttura di dati.
let funTuple2 = ( BMICalculator, fun n -> n * n )
  • È possibile passare una funzione come argomento.
let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]
  • È possibile restituire una funzione come valore di una chiamata di funzione.
let checkFor item =
    let functionToReturn = fun lst ->
                           List.exists (fun a -> a = item) lst
    functionToReturn

Per altre informazioni su F#, vedere Informazioni di riferimento sul linguaggio F#.

Esempio

Descrizione

Il codice seguente contiene tutti gli esempi di questo argomento.

Codice

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

Vedi anche