Funções de primeira classeFirst-class functions

Uma característica de definição de linguagens de programação funcional é a elevação de funções para o status de primeira classe.A defining characteristic of functional programming languages is the elevation of functions to first-class status. Você deve ser capaz de fazer com uma função o que você pode fazer com valores dos outros tipos internos e ser capaz de fazer isso com um grau de esforço comparável.You should be able to do with a function whatever you can do with values of the other built-in types, and be able to do so with a comparable degree of effort.

As medidas típicas de status de primeira classe incluem o seguinte:Typical measures of first-class status include the following:

  • Você pode associar funções a identificadores?Can you bind functions to identifiers? Ou seja, você pode dar a eles nomes?That is, can you give them names?

  • É possível armazenar funções em estruturas de dados, como em uma lista?Can you store functions in data structures, such as in a list?

  • Você pode passar uma função como um argumento em uma chamada de função?Can you pass a function as an argument in a function call?

  • Você pode retornar uma função de uma chamada de função?Can you return a function from a function call?

As duas últimas medidas definem o que é conhecido como operações de ordem superior ou funções de ordem superior.The last two measures define what are known as higher-order operations or higher-order functions. As funções de ordem superior aceitam funções como argumentos e retornam funções como o valor de chamadas de função.Higher-order functions accept functions as arguments and return functions as the value of function calls. Essas operações dão suporte a tais fundamentos de programação funcional como funções de mapeamento e composição de funções.These operations support such mainstays of functional programming as mapping functions and composition of functions.

Dê um nome ao valorGive the Value a Name

Se uma função for um valor de primeira classe, você deverá ser capaz de nomeá-la, assim como você pode nomear inteiros, cadeias de caracteres e outros tipos internos.If a function is a first-class value, you must be able to name it, just as you can name integers, strings, and other built-in types. Isso é referenciado na literatura de programação funcional como associação de um identificador a um valor.This is referred to in functional programming literature as binding an identifier to a value. F # usa let associações para associar nomes a valores: let <identifier> = <value> .F# uses let bindings to bind names to values: let <identifier> = <value>. O código a seguir mostra dois exemplos.The following code shows two examples.

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

Você pode nomear uma função com a mesma facilidade.You can name a function just as easily. O exemplo a seguir define uma função chamada squareIt ligando o identificador squareIt à expressão lambda fun n -> n * n .The following example defines a function named squareIt by binding the identifier squareIt to the lambda expression fun n -> n * n. squareItA função tem um parâmetro, n e retorna o quadrado desse parâmetro.Function squareIt has one parameter, n, and it returns the square of that parameter.

let squareIt = fun n -> n * n

O F # fornece a seguinte sintaxe mais concisa para obter o mesmo resultado com menos digitação.F# provides the following more concise syntax to achieve the same result with less typing.

let squareIt2 n = n * n

Os exemplos a seguir usam principalmente o primeiro estilo, let <function-name> = <lambda-expression> , para enfatizar as semelhanças entre a declaração de funções e a declaração de outros tipos de valores.The examples that follow mostly use the first style, let <function-name> = <lambda-expression>, to emphasize the similarities between the declaration of functions and the declaration of other types of values. No entanto, todas as funções nomeadas também podem ser escritas com a sintaxe concisa.However, all the named functions can also be written with the concise syntax. Alguns dos exemplos são escritos de ambas as maneiras.Some of the examples are written in both ways.

Armazenar o valor em uma estrutura de dadosStore the Value in a Data Structure

Um valor de primeira classe pode ser armazenado em uma estrutura de dados.A first-class value can be stored in a data structure. O código a seguir mostra exemplos que armazenam valores em listas e em tuplas.The following code shows examples that store values in lists and in 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 )

Para verificar se um nome de função armazenado em uma tupla, na verdade, é avaliado como uma função, o exemplo a seguir usa os fst snd operadores e para extrair o primeiro e o segundo elementos da tupla funAndArgTuple .To verify that a function name stored in a tuple does in fact evaluate to a function, the following example uses the fst and snd operators to extract the first and second elements from tuple funAndArgTuple. O primeiro elemento na tupla é squareIt e o segundo elemento é num .The first element in the tuple is squareIt and the second element is num. numO identificador está associado em um exemplo anterior ao inteiro 10, um argumento válido para a squareIt função.Identifier num is bound in a previous example to integer 10, a valid argument for the squareIt function. A segunda expressão aplica o primeiro elemento na tupla ao segundo elemento na tupla: squareIt num .The second expression applies the first element in the tuple to the second element in the 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))

Da mesma forma, assim como o identificador num e o inteiro 10 podem ser usados de maneira intercambiável, portanto, pode identificador squareIt e expressão lambda fun n -> n * n .Similarly, just as identifier num and integer 10 can be used interchangeably, so can identifier squareIt and lambda expression 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))

Passar o valor como um argumentoPass the Value as an Argument

Se um valor tiver o status de primeira classe em um idioma, você poderá passá-lo como um argumento para uma função.If a value has first-class status in a language, you can pass it as an argument to a function. Por exemplo, é comum passar inteiros e cadeias de caracteres como argumentos.For example, it is common to pass integers and strings as arguments. O código a seguir mostra inteiros e cadeias de caracteres passados como argumentos em F #.The following code shows integers and strings passed as arguments 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 as funções tiverem o status de primeira classe, você deverá ser capaz de passá-las como argumentos da mesma maneira.If functions have first-class status, you must be able to pass them as arguments in the same way. Lembre-se de que essa é a primeira característica das funções de ordem superior.Remember that this is the first characteristic of higher-order functions.

No exemplo a seguir, a função applyIt tem dois parâmetros op e arg .In the following example, function applyIt has two parameters, op and arg. Se você enviar em uma função que tenha um parâmetro para op e um argumento apropriado para a função para arg , a função retornará o resultado da aplicação op de arg .If you send in a function that has one parameter for op and an appropriate argument for the function to arg, the function returns the result of applying op to arg. No exemplo a seguir, o argumento de função e o argumento de inteiro são enviados da mesma maneira, usando seus nomes.In the following example, both the function argument and the integer argument are sent in the same way, by using their names.

// 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 baseia-se em abstrações comuns em linguagens de programação funcionais, como operações de mapeamento ou de filtro.The ability to send a function as an argument to another function underlies common abstractions in functional programming languages, such as map or filter operations. Uma operação de mapa, por exemplo, é uma função de ordem superior que captura a computação compartilhada por funções que passam por uma lista, fazem algo para cada elemento e, em seguida, retornam uma lista dos resultados.A map operation, for example, is a higher-order function that captures the computation shared by functions that step through a list, do something to each element, and then return a list of the results. Você pode desejar incrementar cada elemento em uma lista de inteiros ou para quadradoar cada elemento ou para alterar cada elemento em uma lista de cadeias de caracteres para letras maiúsculas.You might want to increment each element in a list of integers, or to square each element, or to change each element in a list of strings to uppercase. A parte propensa a erros da computação é o processo recursivo que percorre a lista e cria uma lista dos resultados a serem retornados.The error-prone part of the computation is the recursive process that steps through the list and builds a list of the results to return. Essa parte é capturada na função de mapeamento.That part is captured in the mapping function. Tudo o que você precisa escrever para um aplicativo específico é a função que você deseja aplicar a cada elemento de lista individualmente (adicionando, elevando, alterando maiúsculas e minúsculas).All you have to write for a particular application is the function that you want to apply to each list element individually (adding, squaring, changing case). Essa função é enviada como um argumento para a função de mapeamento, assim como squareIt é enviada para applyIt no exemplo anterior.That function is sent as an argument to the mapping function, just as squareIt is sent to applyIt in the previous example.

O F # fornece métodos de mapa para a maioria dos tipos de coleção, incluindo listas, matrizese sequências.F# provides map methods for most collection types, including lists, arrays, and sequences. Os exemplos a seguir usam listas.The following examples use lists. A sintaxe é List.map <the function> <the list>.The syntax is 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.For more information, see Lists.

Retornar o valor de uma chamada de funçãoReturn the Value from a Function Call

Por fim, se uma função tiver o status de primeira classe em um idioma, você deverá ser capaz de retorná-la como o valor de uma chamada de função, assim como retorna outros tipos, como inteiros e cadeias de caracteres.Finally, if a function has first-class status in a language, you must be able to return it as the value of a function call, just as you return other types, such as integers and strings.

As chamadas de função a seguir retornam inteiros e as exibem.The following function calls return integers and display them.

// 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 chamada de função a seguir retorna uma cadeia de caracteres.The following function call returns a string.

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

A chamada de função a seguir, declarada embutida, retorna um valor booliano.The following function call, declared inline, returns a Boolean value. O valor exibido é True .The value displayed is 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 ordem superior.The ability to return a function as the value of a function call is the second characteristic of higher-order functions. No exemplo a seguir, checkFor é definido como uma função que usa um argumento, item e retorna uma nova função como seu valor.In the following example, checkFor is defined to be a function that takes one argument, item, and returns a new function as its value. A função retornada usa uma lista como seu argumento, lst e procura item em lst .The returned function takes a list as its argument, lst, and searches for item in lst. Se item estiver presente, a função retornará true .If item is present, the function returns true. Se item não estiver presente, a função retornará false .If item is not present, the function returns false. Como na seção anterior, o código a seguir usa uma função de lista fornecida, list. Exists, para pesquisar a lista.As in the previous section, the following code uses a provided list function, List.exists, to search the list.

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 usa um argumento, uma lista e pesquisa 7 na lista.The following code uses checkFor to create a new function that takes one argument, a list, and searches for 7 in the list.

// 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.The following example uses the first-class status of functions in F# to declare a function, compose, that returns a composition of two function arguments.

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

Observação

Para obter uma versão ainda mais curta, consulte a seção a seguir, "na forma curried Functions".For an even shorter version, see the following section, "Curried Functions."

O código a seguir envia duas funções como argumentos para compose , que usam um único argumento do mesmo tipo.The following code sends two functions as arguments to compose, both of which take a single argument of the same type. O valor de retorno é uma nova função que é uma composição dos dois argumentos de função.The return value is a new function that is a composition of the two function arguments.

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

Observação

O F # fornece dois operadores << e >> , que compõem funções.F# provides two operators, << and >>, that compose functions. Por exemplo, let squareAndDouble2 = doubleIt << squareIt é equivalente a let squareAndDouble = compose doubleIt squareIt no exemplo anterior.For example, let squareAndDouble2 = doubleIt << squareIt is equivalent to let squareAndDouble = compose doubleIt squareIt in the previous example.

O exemplo a seguir de retornar uma função como o valor de uma chamada de função cria um jogo de adivinhação simples.The following example of returning a function as the value of a function call creates a simple guessing game. Para criar um jogo, chame makeGame com o valor que você deseja que alguém Adivinhe envie target .To create a game, call makeGame with the value that you want someone to guess sent in for target. O valor de retorno da função makeGame é uma função que usa um argumento (a estimativa) e informa se a estimativa está correta.The return value from function makeGame is a function that takes one argument (the guess) and reports whether the guess is correct.

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 .The following code calls makeGame, sending the value 7 for target. playGameO identificador está associado à expressão lambda retornada.Identifier playGame is bound to the returned lambda expression. Portanto, playGame é uma função que usa como um valor de um argumento para guess .Therefore, playGame is a function that takes as its one argument a value for 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 na forma curriedCurried Functions

Muitos dos exemplos na seção anterior podem ser escritos de forma mais concisa aproveitando as currying implícitas em declarações de função F #.Many of the examples in the previous section can be written more concisely by taking advantage of the implicit currying in F# function declarations. Currying é um processo que transforma uma função que tem mais de um parâmetro em uma série de funções inseridas, cada uma com um único parâmetro.Currying is a process that transforms a function that has more than one parameter into a series of embedded functions, each of which has a single parameter. Em F #, as funções que têm mais de um parâmetro são inerentemente na forma curried.In F#, functions that have more than one parameter are inherently curried. Por exemplo, compose da seção anterior pode ser escrito conforme mostrado no estilo conciso a seguir, com três parâmetros.For example, compose from the previous section can be written as shown in the following concise style, with three parameters.

let compose4 op1 op2 n = op1 (op2 n)

No entanto, o resultado é uma função de um parâmetro que retorna uma função de um parâmetro que, por sua vez, retorna outra função de um parâmetro, como mostrado em compose4curried .However, the result is a function of one parameter that returns a function of one parameter that in turn returns another function of one parameter, as shown in compose4curried.

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

Você pode acessar essa função de várias maneiras.You can access this function in several ways. Cada um dos exemplos a seguir retorna e exibe 18.Each of the following examples returns and displays 18. Você pode substituir compose4 por compose4curried em qualquer um dos exemplos.You can replace compose4 with compose4curried in any of the examples.

// 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 se a função ainda funciona como antes, tente os casos de teste originais novamente.To verify that the function still works as it did before, try the original test cases again.

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)

Observação

Você pode restringir currying por meio de parâmetros delimitadores em tuplas.You can restrict currying by enclosing parameters in tuples. Para obter mais informações, consulte "padrões de parâmetro" em parâmetros e argumentos.For more information, see "Parameter Patterns" in Parameters and Arguments.

O exemplo a seguir usa o currying implícito para gravar uma versão mais curta do makeGame .The following example uses implicit currying to write a shorter version of makeGame. Os detalhes de como makeGame construções e Devoluções da game função são menos explícitos nesse formato, mas você pode verificar usando os casos de teste originais que o resultado é o mesmo.The details of how makeGame constructs and returns the game function are less explicit in this format, but you can verify by using the original test cases that the result is the same.

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 currying, consulte "aplicativo parcial de argumentos" em funções.For more information about currying, see "Partial Application of Arguments" in Functions.

Identificador e definição de função são intercambiáveisIdentifier and Function Definition Are Interchangeable

O nome da variável num nos exemplos anteriores é avaliado como o inteiro 10, e não é surpresa que o local num seja válido, 10 também é válido.The variable name num in the previous examples evaluates to the integer 10, and it is no surprise that where num is valid, 10 is also valid. O mesmo vale para identificadores de função e seus valores: em qualquer lugar, o nome da função pode ser usado, a expressão lambda à qual ele está associado pode ser usada.The same is true of function identifiers and their values: anywhere the name of the function can be used, the lambda expression to which it is bound can be used.

O exemplo a seguir define uma Boolean função chamada isNegative e, em seguida, usa o nome da função e a definição da função de forma intercambiável.The following example defines a Boolean function called isNegative, and then uses the name of the function and the definition of the function interchangeably. Os próximos três exemplos retornam e exibem False .The next three examples all return and display 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 levá-lo um passo adiante, substitua o valor que applyIt está associado a para applyIt .To take it one step further, substitute the value that applyIt is bound to for applyIt.

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

Funções são valores de primeira classe em F#Functions Are First-Class Values in F#

Os exemplos nas seções anteriores demonstram que as funções em F # atendem aos critérios para serem valores de primeira classe em F #:The examples in the previous sections demonstrate that functions in F# satisfy the criteria for being first-class values in F#:

  • Você pode associar um identificador a uma definição de função.You can bind an identifier to a function definition.
let squareIt = fun n -> n * n
  • Você pode armazenar uma função em uma estrutura de dados.You can store a function in a data structure.
let funTuple2 = ( BMICalculator, fun n -> n * n )
  • Você pode passar uma função como um argumento.You can pass a function as an argument.
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.You can return a function as the value of a function call.
let checkFor item =
    let functionToReturn = fun lst ->
                           List.exists (fun a -> a = item) lst
    functionToReturn

Para obter mais informações sobre F #, consulte a referência de linguagem f #.For more information about F#, see the F# Language Reference.

ExemploExample

DescriçãoDescription

O código a seguir contém todos os exemplos neste tópico.The following code contains all the examples in this topic.

CódigoCode

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

Confira tambémSee also