Поделиться через


Функции как значения первого класса (F#)

Определяющей характеристикой функциональных языков программирования является повышение функций до состояния первого класса. С функцией можно совершать те же действия, что и со значениями других встроенных типов, с сопоставимым объемом усилий.

Ниже представлены типичные вопросы для оценки состояния первого класса.

  • Можно ли привязать идентификатор к значению? Если да, можно ли присвоить ему имя?

  • Можно ли хранить значение в структуре данных, такой как список?

  • Можно ли передать значение в качестве аргумента в вызов функции?

  • Можно ли вернуть значение в качестве значения вызова функции?

Последние два вопроса оценки определяют то, что известно как операции высшего порядка или функции высшего порядка. Функции высшего порядка принимают функции в качестве аргументов и возвращают функции в качестве значения вызова функции. Эти операции поддерживают такие основы функционального программирования как функции сопоставления и объединение функций.

Присвоение имени значению

Если функция является значением первого класса, должна быть возможность присвоить ей имя так же, как и целочисленным, строковым и другим встроенным типам. В литературе о функциональном программировании это называется привязкой идентификатора к значению. F# использует выражения let для привязки имен к значениям: let <identifier> = <value>. В следующем коде показано два примера.

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

Функции можно легко присвоить имя. В следующем примере определяется функция с именем squareIt путем связывания идентификатора squareIt с лямбда-выражением fun n -> n * n. У функции squareIt имеется один параметр n, и она возвращает квадрат этого параметра.

let squareIt = fun n -> n * n

F# предоставляет следующий, более краткий, синтаксис для достижения того же результата с меньшим количеством написанного текста.

let squareIt2 n = n * n

В приведенных ниже примерах в основном используется первый стиль (let <function-name> = <lambda-expression>), чтобы подчеркнуть сходства объявления функций и объявления других типов значений. Кроме того, синтаксис всех именованных функций также может быть более кратким. В некоторых примерах представлено два варианта написания.

Хранение значения в структуре данных

Значение первого класса может храниться в структуре данных. В следующем коде приведены примеры, демонстрирующие хранение значений в списках и кортежах.

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

Чтобы убедиться, что имя функции, хранимое в кортеже, фактически выполняет вычисление функции, в следующем примере операторы fst и snd используются для извлечения первого и второго элемента из кортежа funAndArgTuple. Первый элемент в кортеже называется squareIt, второй — num. Идентификатор num в предыдущем примере привязан к целому числу 10, которое является допустимым аргументом для функции squareIt. Во втором выражении первый элемент кортежа применяется ко второму: 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))

Подобным образом идентификатор num и целое число 10 могут быть взаимозаменяемыми, как идентификатор squareIt и лямбда-выражение 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))

Передача значения в качестве аргумента

Если значение имеет состояние первого класса в языке, его можно передавать в качестве аргумента в функцию. Например, обычной практикой является передача целых чисел и строк в качестве аргументов. В следующем коде 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)

Если функции находятся в состоянии первого класса, их можно таким же образом передавать в качестве аргументов. Помните, что это первая характеристика функций высшего порядка.

В следующем примере у функции applyIt имеется два параметра: op и arg. Если отправить функцию, у которой имеется один параметр для op и соответствующий функции аргумент в arg, функция вернет результат применения op к arg. В следующем примере аргумент функции и целочисленный аргумент отправляются таким же образом с помощью имен.

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

Возможность отправления функции в качестве аргумента другой функции лежит в основе типичных абстракций функциональных языков программирования, таких как операции сопоставления или фильтрации. Операция сопоставления, например, является функцией высшего порядка, захватывающей общее вычисление для функций, которые проходят по списку, выполняют некоторые действия с каждым элементом, а потом возвращают список результатов. Можно увеличить значение каждого элемента в списке целых чисел, вычислить квадрат каждого элемента или перевести каждый элемент в списке строк в верхний регистр. Подверженная ошибкам часть вычисления является рекурсивным процессом, который проходит по списку и выполняет построение списка возвращаемых результатов. Эта часть захватывается функцией сопоставления. Для определенного приложения необходимо написать только функцию, которую требуется применить к каждому элементу списка по отдельности (добавление, возведение в квадрат, изменение регистра). Эта функция отправляется в качестве аргумента в функцию сопоставления точно так же, как в предыдущем примере squareIt отправляется в applyIt.

F# предоставляет методы сопоставления для большинства типов коллекций, включая списки, массивы и наборы. В следующих примерах используются списки. Синтаксис: 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

Дополнительные сведения см. в разделе Списки (F#).

Возвращение значения из вызова функции

Наконец, если функция имеет состояние первого класса в языке, ее можно вернуть в качестве значения вызова функции так же, как возвращаются другие типы, такие как целочисленные и строковые.

Следующие вызовы функции возвращают целые числа и отображают их.

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

При вызове следующей функции возвращается строка.

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

Следующий вызов функции, объявленный внутри нее, возвращает логическое значение. Отображаемое значение — True.

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

Возможность возвращать функцию в качестве значения вызова функции является второй характеристикой функций высшего порядка. В следующем примере checkFor определяется в качестве функции, которая принимает один аргумент item и возвращает новую функцию в качестве его значения. Возвращаемая функция принимает список в качестве аргумента lst и выполняет поиск item в lst. Если item существует, функция возвращает true. Если item не существует, функция возвращает false. Как и в предыдущем разделе, в следующем коде используется функция списка List.exists для поиска в списке.

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

В следующем коде используется checkFor для создания новой функции, которая принимает один аргумент (список) и выполняет поиск числа 7 в списке.

// integerList and stringList were defined earlier.
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
//let stringList = [ "one"; "two"; "three" ]

// The returned function is given the name checkFor7. 
let checkFor7 = checkFor 7

// The result displayed when checkFor7 is applied to integerList is True.
System.Console.WriteLine(checkFor7 integerList)

// The following code repeats the process for "seven" in stringList.
let checkForSeven = checkFor "seven"

// The result displayed is False.
System.Console.WriteLine(checkForSeven stringList)

В следующем примере используется состояние первого класса функций в F# для объявления функции compose, которая возвращает композицию двух аргументов функции.

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

Примечание

Более краткую версию см. в разделе "Каррированные функции".

Следующий код отправляет две функции в качестве аргументов compose, каждая из которых принимает один аргумент того же типа. Возвращаемое значение — новая функция, которая является композицией двух аргументов функции.

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

Примечание

В языке F# имеются два оператора << и >> из которых состоят функции.Например, в предыдущем примере let squareAndDouble2 = doubleIt << squareIt эквивалентно let squareAndDouble = compose doubleIt squareIt.

В следующем примере возврата функции в качестве значения вызова функции создается простая игра по угадыванию. Чтобы создать игру, вызовите makeGame со значением, которое требуется угадать, отправленным для target. Возвращаемое значение функции makeGame является функцией, которая принимает один аргумент (предположение) и сообщает, верно ли предположение.

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

В следующем коде вызывается функция makeGame и отсылается число 7 в target. Идентификатор playGame привязан к возвращаемому лямбда-выражению. Таким образом playGame представляет собой функцию, которая принимает в качестве одного аргумента значение 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!

Каррированные функции

Многие примеры из предыдущего раздела можно написать более кратко, используя преимущества неявного каррирования при объявлении функций в F#. Каррирование — это процесс преобразования функции, которая содержит несколько параметров, в ряд внедренных функций, каждая из которых имеет один параметр. В F# функции, имеющие несколько параметров, каррируются. Например, compose из предыдущего раздела можно написать, как показано в следующем кратком стиле, с тремя параметрами.

let compose4 op1 op2 n = op1 (op2 n)

Однако результатом будет являться функция одного параметра, которая возвращает функцию одного параметра, которая, в свою очередь, возвращает другую функцию одного параметра, как показано в compose4curried.

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

Получить доступ к этой функции можно несколькими способами. Каждый из приведенных ниже примеров возвращает и отображает число 18. В любом из примеров compose4 можно заменить на compose4curried.

// Access one layer at a time.
System.Console.WriteLine(((compose4 doubleIt) squareIt) 3)

// Access as in the original compose examples, sending arguments for 
// op1 and op2, then applying the resulting function to a value.
System.Console.WriteLine((compose4 doubleIt squareIt) 3)

// Access by sending all three arguments at the same time.
System.Console.WriteLine(compose4 doubleIt squareIt 3)

Чтобы убедиться, что функция все еще работает так же, как и прежде, повторите исходные тестовые случаи.

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)

Примечание

Можно запретить каррирование, поместив параметры в кортежи.Дополнительные сведения см. в подразделе "Шаблоны параметров" раздела Параметры и аргументы (F#).

В следующем примере используется неявное каррирование для написания краткой версии makeGame. Сведения о том, как makeGame создает и возвращает функцию game являются менее явными в этом формате, но с помощью исходных тестовых случаев можно проверить, что результат будет таким же.

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'

Дополнительные сведения о каррировании см. в подразделе "Частичное применение аргументов" раздела Функции (F#).

Идентификатор и определение функции являются взаимозаменяемыми

Имя переменной num в предыдущих примерах имеет значение целого числа 10, и не удивительно, что где num допустимо, число 10 тоже допустимо. Также это справедливо для идентификаторов функций и их значений: везде, где может быть использовано имя функции, можно использовать связанное с ним лямбда-выражение.

В следующем примере определяется функция Boolean с именем isNegative, а затем поочередно используется имя функции и определение функции. Следующие три примера возвращают и отображают 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) 

Забегая на шаг вперед, в applyIt можно подставить значение, с которым связана функция applyIt.

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

Функции являются значениями первого класса в F#

В примерах из предыдущих разделов демонстрируется, что функции в 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
    

Дополнительные сведения о F# см. в разделе Новые возможности Visual F# 2010 или Справочник по языку F#.

Пример

Описание

В следующем коде содержатся все примеры данного раздела.

Код


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

См. также

Ссылки

Кортежи (F#)

Функции (F#)

Привязки let (F#)

Лямбда-выражения: ключевое слово fun (F#)

Другие ресурсы

Списки (F#)