Partager via


Fonctions comme valeurs de première classe (F#)

Les langages de programmation fonctionnelle sont caractérisés par l'élévation des fonctions à l'état de première classe. Vous devez pouvoir faire avec une fonction tout ce que vous pouvez faire avec les valeurs des autres types intégrés, et ce avec un degré comparable d'effort.

L'état de première classe se mesure généralement de la façon suivante :

  • Pouvez-vous lier un identificateur à la valeur ? Autrement dit, pouvez-vous lui attribuer un nom ?

  • Pouvez-vous stocker la valeur dans une structure de données (liste, par exemple) ?

  • Pouvez-vous passer la valeur en tant qu'argument dans un appel de fonction ?

  • Pouvez-vous retourner la valeur en tant que valeur d'un appel de fonction ?

Les deux dernières mesures définissent ce qui est désigné par opérations d'ordre supérieur ou fonctions d'ordre supérieur. Les fonctions d'ordre supérieur acceptent des fonctions en tant qu'arguments et retournent des fonctions en tant que valeur d'appels de fonction. Ces opérations prennent en charge des éléments aussi essentiels de la programmation fonctionnelle que le mappage des fonctions et la composition de fonctions.

Attribuer un nom à la valeur

Lorsqu'une fonction est une valeur de première classe, vous devez pouvoir lui attribuer un nom, de la même manière que vous le feriez avec des entiers, des chaînes et autres types intégrés. En programmation fonctionnelle, cela est désigné par « lier un identificateur à une valeur ». F# utilise des expressions let pour lier des noms à des valeurs : let <identifier> = <value>. Le code suivant montre deux exemples.

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

Vous pouvez nommer une fonction aussi facilement que cela. L'exemple suivant définit une fonction nommée squareIt en liant l'identificateur squareIt à l'expression lambda fun n -> n * n. La fonction squareIt possède un paramètre (n) et elle retourne le carré de ce paramètre.

let squareIt = fun n -> n * n

F# fournit la syntaxe suivante, plus concise, pour parvenir au même résultat avec moins de saisie.

let squareIt2 n = n * n

Les exemples qui suivent utilisent essentiellement le premier style (let <function-name> = <lambda-expression>) pour accentuer les ressemblances entre la déclaration de fonctions et la déclaration d'autres types de valeurs. Toutes les fonctions nommées peuvent toutefois également être écrites avec une syntaxe concise. Certains exemples sont écrits des deux façons.

Stocker la valeur dans une structure de données

Une valeur de première classe peut être stockée dans une structure de données. Le code suivant montre des exemples qui stockent des valeurs dans des listes et des tuples.

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

Pour vérifier qu'un nom de fonction stocké dans un tuple a en fait la valeur d'une fonction, l'exemple suivant utilise les opérateurs snd et fst pour extraire les premier et deuxième éléments du tuple funAndArgTuple. Le premier élément du tuple est squareIt et le deuxième élément est num. L'identificateur num est lié dans un précédent exemple à l'entier 10, qui est un argument valide pour la fonction squareIt. La deuxième expression applique le premier élément du tuple au deuxième élément du tuple : 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))

Tout comme l'identificateur num et l'entier 10, l'identificateur squareIt et l'expression lambda fun n -> n * n peuvent être utilisés de manière interchangeable.

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

Passer la valeur en tant qu'argument

Lorsque l'état d'une valeur est de première classe dans un langage, vous pouvez la passer en tant qu'argument à une fonction. Par exemple, il est fréquent de passer des entiers et des chaînes en tant qu'arguments. Le code suivant montre des entiers et des chaînes passés en tant qu'arguments en 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)

Lorsque l'état des fonctions est de première classe, vous devez de la même façon pouvoir les passer en tant qu'arguments. N'oubliez pas qu'il s'agit de la première caractéristique des fonctions d'ordre supérieur.

Dans l'exemple suivant, la fonction applyIt possède deux paramètres (op et arg). Si vous envoyez une fonction qui possède un paramètre pour op et un argument approprié pour la fonction à arg, la fonction retourne le résultat de l'application de op à arg. Dans l'exemple suivant, l'argument de fonction et l'argument d'entier sont tous deux envoyés de la même façon, sur la base de leur nom.

// 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é d'envoyer une fonction en tant qu'argument à une autre fonction repose à la base d'abstractions communes dans les langages de programmation fonctionnelle (par exemple, opérations de mappage ou de filtrage). Une opération de mappage est, par exemple, une fonction d'ordre supérieur qui capture le calcul partagé entre des fonctions qui progressent dans une liste, apportent des modifications à chaque élément, puis retournent la liste des résultats. Vous pouvez incrémenter chaque élément dans une liste d'entiers, mettre au carré chaque élément ou encore mettre en majuscule chaque élément d'une liste de chaînes. La partie du calcul sujette à erreur concerne le processus récursif qui progresse dans la liste et génère la liste des résultats à retourner. Cette partie est capturée dans la fonction de mappage. Tout ce que vous avez à écrire pour une application particulière est la fonction que vous souhaitez appliquer à chacun des éléments de la liste (ajout, mise au carré, modification de la casse). Cette fonction est envoyée en tant qu'argument à la fonction de mappage, de la même manière que squareIt est envoyé à applyIt dans l'exemple précédent.

F# fournit des méthodes de mappage pour la plupart des types de collections, parmi lesquels les listes, les tableaux et les jeux. Les exemples suivants utilisent des listes. La syntaxe est 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

Pour plus d'informations, consultez Listes (F#).

Retourner la valeur d'un appel de fonction

Lorsque l'état d'une fonction est de première classe dans un langage, vous devez pouvoir le retourner en tant que valeur d'un appel de fonction, de la même manière que vous le feriez avec d'autres types, comme les entiers et les chaînes.

Les appels de fonction suivants retournent des entiers et les affichent.

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

L'appel de fonction suivant retourne une chaîne.

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

L'appel de fonction suivant, déclaré inline, retourne une valeur booléenne. La valeur affichée est True.

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

La possibilité de retourner une fonction en tant que valeur d'un appel de fonction est la deuxième caractéristique des fonctions d'ordre supérieur. Dans l'exemple suivant, checkFor est défini en tant que fonction qui prend un argument (item) et retourne une nouvelle fonction en tant que valeur. La fonction retournée prend une liste en tant qu'argument lui appartenant (lst) et recherche item dans lst. Si item y figure, la fonction retourne la valeur true. Si item n'y figure pas, la fonction retourne la valeur false. Comme dans la section précédente, le code suivant utilise une fonction de liste fournie (List.exists) pour effectuer des recherches dans la liste.

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

Le code suivant utilise checkFor pour créer une fonction qui prend un argument, une liste et recherche 7 dans la liste.

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

L'exemple suivant utilise l'état de première classe de fonctions en F# pour déclarer une fonction (compose), laquelle retourne une composition de deux arguments de fonction.

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

Notes

Pour obtenir une version encore plus courte, consultez la section « Fonctions curryfiées ».

Le code suivant envoie deux fonctions en tant qu'arguments à compose, chacune d'entre elles prenant un seul argument de même type. La valeur de retour est une nouvelle fonction qui est une composition des deux arguments de fonction.

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

Notes

F# fournit deux opérateurs (<< et >>), lesquels composent des fonctions. Par exemple, let squareAndDouble2 = doubleIt << squareIt est équivalent à let squareAndDouble = compose doubleIt squareIt dans l'exemple précédent.

L'exemple suivant, qui illustre le retour d'une fonction en tant que valeur d'un appel de fonction, crée un jeu d'estimation simple. Pour créer un jeu, appelez makeGame avec la valeur à deviner définie pour être envoyée à target. La valeur de retour de la fonction makeGame est une fonction qui prend un argument (l'estimation) et indique si cette estimation est correcte.

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

Le code suivant appelle makeGame, en envoyant la valeur 7 à target. L'identificateur playGame est lié à l'expression lambda retournée. playGame est par conséquent une fonction qui prend en tant qu'argument unique une valeur définie pour 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!

Fonctions curryfiées

La plupart des exemples de la section précédente peuvent être écrits de manière encore plus concise, en tirant parti de la curryfication implicite dans les déclarations de fonction F#. La curryfication est un processus qui transforme une fonction, qui possède plusieurs paramètres, en série de fonctions intégrées, chacune de ces fonctions possédant un seul paramètre. En F#, les fonctions qui possèdent plusieurs paramètres sont intrinsèquement curryfiées. Par exemple, dans la section précédente, compose peut être écrit comme indiqué dans le style concis suivant, avec trois paramètres.

let compose4 op1 op2 n = op1 (op2 n)

Il en résulte toutefois une fonction d'un paramètre qui retourne une fonction d'un paramètre, qui retourne à son tour une autre fonction d'un paramètre, comme indiqué dans compose4curried.

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

Vous pouvez accéder de plusieurs façons à cette fonction. Chacun des exemples suivants retourne et affiche 18. Vous pouvez remplacer compose4 par compose4curried dans chacun des exemples.

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

Pour vérifier que la fonction continue à fonctionner comme auparavant, réessayez les cas de test d'origine.

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)

Notes

Vous pouvez limiter la curryfication en englobant les paramètres dans les tuples. Pour plus d'informations, consultez « Modèles de paramètre » dans Paramètres et arguments (F#).

L'exemple suivant utilise la curryfication implicite pour écrire une version plus courte de makeGame. La façon dont makeGame construit et retourne la fonction game n'est pas explicitement détaillée dans ce format, mais vous pouvez vérifier que le résultat est identique avec les cas de test d'origine.

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'

Pour plus d'informations sur la curryfication, consultez « Application partielle d'arguments » dans Fonctions (F#).

Interchangeabilité de l'identificateur et de la définition de fonction

Le nom de la variable num dans les exemples précédents a la valeur entière 10 et il n'est pas surprenant que lorsque num est valide, 10 le soit également. Cela vaut aussi pour les identificateurs de fonction et leur valeur : là où le nom de la fonction peut être utilisé, l'expression lambda à laquelle il est lié peut être utilisée.

L'exemple suivant définit une fonction Boolean appelée isNegative, puis utilise de manière interchangeable le nom de la fonction et la définition de la fonction. Les trois exemples suivants retournent et affichent tous 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) 

Pour aller encore plus loin, remplacez la valeur à laquelle applyIt est lié par applyIt.

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

Les fonctions sont des valeurs de première classe en F#

Les exemples des sections précédentes montrent que les fonctions F# répondent aux critères de valeurs de première classe en F# :

  • Vous pouvez lier un identificateur à une définition de fonction.

    let squareIt = fun n -> n * n
    
  • Vous pouvez stocker une fonction dans une structure de données.

    let funTuple2 = ( BMICalculator, fun n -> n * n )
    
  • Vous pouvez passer une fonction en tant qu'argument.

    let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]
    
  • Vous pouvez retourner une fonction en tant que valeur d'un appel de fonction.

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

Pour plus d'informations sur F#, consultez Nouveautés de Visual F# 2010 ou Référence du langage F#.

Exemple

Description

Le code suivant contient tous les exemples de cette rubrique.

Code


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

Voir aussi

Référence

Tuples (F#)

Fonctions (F#)

Liaisons let (F#)

Expressions lambda : mot clé fun (F#)

Autres ressources

Listes (F#)