Funções como valores de primeira classe (F#)

Uma característica de definição de linguagens de programação funcionais é a elevação de funções para o status de primeira classe. Você deve poder fazer com uma função tudo o que você poderia fazer com valores dos outros tipos internos, e poderá fazer isso com um grau comparável de esforço.

Medidas típicas de status de primeira classe incluem o seguinte:

  • Você pode associar um identificador ao valor? Isto é, você pode dar-lhe um nome?

  • Você pode armazenar o valor em um estrutura de dados, como uma lista?

  • Você pode passar o valor como um argumento em uma chamada de função?

  • Você pode retornar o valor como o valor de uma chamada de função?

As duas últimas medidas definem o que são conhecidas como operações de pedido superior ou funções de pedido superior. Funções de pedido superior aceitam funções como argumentos e funções como o valor de retorno de chamadas de função. Essas operações suportam funcionalidades essenciais de programação funcional como mapeamento de funções e composição de funções.

Forneça um nome para o valor

Se uma função é um valor de primeira classe, você deve ser capaz nomeá-la, exatamente como você pode nomear inteiros, cadeias de caracteres, e outros tipos internos. Isso é conhecido na literatura funcional de programação como associar um identificador a um valor. F# usa expressões let para associar nomes a valores: let <identifier> = <value>. O exemplo de código a seguir ilustra isto:

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

Você pode nomear uma função da mesma forma facilmente. O exemplo a seguir define uma função chamada squareIt associando o identificador squareIt a expressão lambdafun n -> n * n. A função squareIt tem um parâmetro, n, e retorna o quadrado do parâmetro.

let squareIt = fun n -> n * n

F# fornece a seguinte sintaxe mais concisa para obter o mesmo resultado com menos digitação.

let squareIt2 n = n * n

Os exemplos a seguir usam basicamente o primeiro estilo, let <function-name> = <lambda-expression>, para enfatizar as semelhanças entre a declaração de funções e as de outros tipos de valores. No entanto, todas as funções nomeadas também podem ser escritas com a sintaxe concisa. Alguns exemplos são gravados em ambas as direções.

Armazenar o valor em uma estrutura de dados

Um valor de primeira classe pode ser armazenado em uma estrutura de dados. O código a seguir mostra exemplos que armazenam valores nas listas e em tuplas.

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

Para verificar se um nome de função armazenado em um tupla aponta realmente para uma função, o exemplo a seguir usa fst e os operadores snd para extrair o primeiro e segundo elementos da tupla funAndArgTuple. O primeiro elemento no tupla é squareIt e o segundo elemento é num. O identificador num está associado em um exemplo anterior ao inteiro 10, um argumento válido para a função squareIt. A segunda expressão aplica o primeiro elemento na tupla ao segundo elemento na 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))

De a mesma forma, assim como o identificador num e o inteiro 10 podem ser usados de maneira intercambiável, também podem o identificador squareIt e a expressão lambda 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))

Passar o valor como um argumento

Se um valor tem o status de primeira classe em uma linguagem, você pode passá-lo como um argumento para uma função. Por exemplo, é comum passar inteiros e cadeias de caracteres como argumentos. O seguinte código mostra inteiros e cadeias de caracteres sendo passados como argumentos em 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 as funções têm o status de primeira classe, você deve ser capaz de transmitir da mesma forma como argumentos. Lembre-se de que esta é a primeira característica de funções de pedido superior.

No exemplo, a função applyIt tem dois parâmetros, op e arg. Se você enviar uma função que tem um parâmetro para op e um argumento apropriado para a função arg, a função retorna o resultado de aplicar op a arg. No exemplo seguinte, tanto o argumento da função quanto o argumento integer são enviados da mesma forma, usando seus nomes.

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

A capacidade de enviar uma função como um argumento para outra função é a base de abstrações comuns em linguagens de programação funcionais, como operações de mapa ou de filtro. Uma operação de mapa, por exemplo, é uma função de pedido superior que captura a computação compartilhada pelas funções que passam através de uma lista, fazem algo a cada elemento, e então retornam uma lista de resultados. Você pode desejar incrementar cada elemento em uma lista de inteiros, ou elevar ao quadrado cada elemento, ou alterar cada elemento em uma lista de cadeias de caracteres para maiúsculas. A parte sujeita a erros de computação é o processo recursivo que passa pela lista e constrói uma lista de resultados para retornar. Essa parte é detectada na função de mapeamento. Tudo o que você precisa escrever para um determinado aplicativo é a função que você deseja aplicar individualmente para cada elemento da lista (adicionando, elevando ao quadrado, alterando para maiúsculas). A função é enviada como um argumento para a função de mapeamento, assim como squareIt é enviado a applyIt no exemplo anterior.

F# fornece os métodos de mapa para a maioria dos tipos de coleção, incluindo listas, matrizes, e conjuntos. Os seguintes exemplos usam listas. A sintaxe é 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

Para obter mais informações, consulte Listas (F#).

Retorna o valor de uma chamada de função

Finalmente, se uma função tem o status de primeira classe em uma linguagem, você deve ser capaz de retorná-lo como o valor de uma chamada de função, exatamente como você retorna outros tipos, como números inteiros e cadeias de caracteres.

As seguintes chamadas de função retornam inteiros e os exibem.

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

A seguinte chamada de função retorna uma cadeia de caracteres.

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

A seguinte chamada de função, declarada inline, retorna um valor Booleano. O valor é exibido True.

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

A capacidade de retornar uma função como o valor de uma chamada de função é a segunda característica de funções de pedido superior. No exemplo, checkFor é definido para ser uma função que recebe um argumento, item, e retorna uma nova função como seu valor. A função retornada utiliza uma lista como seus argumentos, lst, e procura por item em lst. Se item estiver presente, a função retorna true. Se item não está presente, a função retorna false. Como na seção anterior, o código a seguir usa uma função fornecida na lista, List.exists, para pesquisar a lista.

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

O código a seguir usa checkFor para criar uma nova função que recebe um argumento, uma lista, e procura por 7 na lista.

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

O exemplo a seguir usa o status de primeira classe de funções em F# para declarar uma função, compose, que retorna uma composição de dois argumentos de função.

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

Dica

Para uma versão ainda mais curta, consulte a seção “Curried Functions"..

O código a seguir envia duas funções como os argumentos para compose, ambos os quais recebem um único argumento do mesmo tipo. O valor de retorno é uma nova função que é uma composição dos dois argumentos de função.

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

Dica

F# fornece dois operadores, << e >>, que compõem funções.Por exemplo, let squareAndDouble2 = doubleIt << squareIt é equivalente a let squareAndDouble = compose doubleIt squareIt no exemplo anterior.

O exemplo de retornar uma função como o valor de uma chamada de função cria um jogo de estimativa simples. Para criar um jogo, chame makeGame com o valor que você deseja que alguém adivinhe enviado para target. O valor de retorno da função makeGame é uma função que recebe um argumento (a suposição) e relatórios se a suposição está correta.

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

O código a seguir chama makeGame, enviando o valor 7 para target. O identificador playGame é associado à expressão lambda retornada. Portanto, playGame é uma função que recebe um como seu argumento um valor para 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!

Funções surradas

Muitos dos exemplos na seção anterior podem ser escritos de maneira mais concisa aproveitando o currying implícito em declarações de função de F#. Currying é um processo que torna uma função que tem mais de um parâmetro em uma série de funções inseridas, com cada uma delas tendo um único parâmetro. Em F#, as funções que tem mais de um parâmetro são inerentemente surradas. Por exemplo, compose da seção anterior pode ser escrito como mostrado no exemplo a seguir, conciso estilo com três parâmetros.

let compose4 op1 op2 n = op1 (op2 n)

Entretanto, o resultado é uma função de um parâmetro que retorna uma função de um parâmetro que retorna por sua vez outra função de um parâmetro, conforme mostrado em compose4curried.

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

Você pode acessar essa função de várias maneiras. Cada um dos seguintes exemplos retorna e exibe 18. Você pode substituir compose4 com compose4curried em alguns exemplos.

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

Para verificar que a função ainda funciona como antes, tente as situações de teste originais novamente.

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)

Dica

Você pode restringir o currying incluindo parâmetros em tuplas.Para obter mais informações, consulte “parâmetro modelo” em Parâmetros e argumentos (F#).

O exemplo a seguir usa o currying implícito para gravar uma versão mais curta de makeGame. Os detalhes de como makeGame constrói e retorna a função game são menos explícitos neste formato, mas você pode verificar usando as situações de teste originais que o resultado é o mesmo.

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'

Para obter mais informações sobre o currying, consulte “o aplicativo parcial dos argumentos” em Funções (F#).

O identificador e a definição de função são intercambiáveis

O nome de variável num nos exemplos anteriores avalia para o inteiro 10, e não há surpresa que onde num é válido, 10 também é válido. O mesmo vale para identificadores de função e seus valores: em qualquer lugar que o nome da função pode ser usado, a expressão lambda ao qual está associada pode ser usada.

O exemplo a seguir define uma função Boolean chamada isNegativee em seguida, usa o nome da função e a definição da função de maneira intercambiável. Todos os três exemplos a seguir retornam e exibem 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) 

Para dar um passo adiante, substitua o valor ao qual applyIt está associado para applyIt.

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

Funções são valores de primeira classe em F#

Os exemplos nas seções anteriores demonstram que as funções em F# satisfazem os critérios para ser valores de primeira classe em F#:

  • Você pode associar um identificador a uma definição de função.

    let squareIt = fun n -> n * n
    
  • Você pode armazenar uma função em uma estrutura de dados.

    let funTuple2 = ( BMICalculator, fun n -> n * n )
    
  • Você pode passar uma função como um argumento.

    let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]
    
  • você pode retornar uma função como o valor de uma chamada de função.

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

Para obter mais informações sobre a F#, consulte Referência da linguagem F#.

Exemplo

Descrição

O código a seguir contém todos os exemplos neste tópico.

Código

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

Consulte também

Referência

Tuplas (F#)

Funções (F#)

Associações let (F#)

Expressões lambda: a palavra-chave fun (F#)

Outros recursos

Listas (F#)