Używanie funkcji w języku F#

Prosta definicja funkcji przypomina następującą:

let f x = x + 1

W poprzednim przykładzie nazwa funkcji to , argument to fx, który ma typ , treść funkcji to x + 1, a zwracana wartość jest typu intint.

Definiującą cechę języka F# jest to, że funkcje mają stan pierwszej klasy. Można to zrobić za pomocą funkcji niezależnie od tego, co można zrobić z wartościami innych wbudowanych typów, z porównywalnym stopniem wysiłku.

  • Możesz nadać nazwy wartości funkcji.

  • Funkcje można przechowywać w strukturach danych, takich jak na liście.

  • Funkcję można przekazać jako argument w wywołaniu funkcji.

  • Funkcję można zwrócić z wywołania funkcji.

Nadaj wartości nazwę

Jeśli funkcja jest wartością pierwszej klasy, musisz mieć możliwość nadanie jej nazwy, tak samo jak nazwy liczb całkowitych, ciągów i innych wbudowanych typów. Jest to określane w literaturze programowania funkcjonalnego jako powiązanie identyfikatora z wartością. Język F# używa let powiązań do powiązania nazw z wartościami : let <identifier> = <value>. Poniższy kod przedstawia dwa przykłady.

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

Funkcję można nazwać tak samo łatwo. W poniższym przykładzie zdefiniowano funkcję o nazwie squareIt przez powiązanie identyfikatora squareIt z wyrażeniem fun n -> n * nlambda. Funkcja squareIt ma jeden parametr , na zwraca kwadrat tego parametru.

let squareIt = fun n -> n * n

Język F# udostępnia następującą bardziej zwięzłą składnię, aby osiągnąć ten sam wynik przy mniejszym wpisywaniu.

let squareIt2 n = n * n

Przykłady, które są zgodne głównie z pierwszym stylem, let <function-name> = <lambda-expression>, aby podkreślić podobieństwa między deklaracją funkcji a deklaracją innych typów wartości. Jednak wszystkie nazwane funkcje można również napisać za pomocą zwięzłej składni. Niektóre przykłady są napisane na oba sposoby.

Przechowywanie wartości w strukturze danych

Wartość pierwszej klasy może być przechowywana w strukturze danych. Poniższy kod przedstawia przykłady, które przechowują wartości na listach i w krotkach.

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

Aby sprawdzić, czy nazwa funkcji przechowywana w krotkach rzeczywiście ocenia funkcję, w poniższym przykładzie użyto fst operatorów i snd do wyodrębnienia pierwszych i drugich elementów z krotki funAndArgTuple. Pierwszy element w krotki to squareIt , a drugim elementem jest num. Identyfikator num jest powiązany w poprzednim przykładzie z liczbą całkowitą 10, prawidłowym argumentem squareIt dla funkcji. Drugie wyrażenie stosuje pierwszy element w krotki do drugiego elementu w krotku: 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))

Podobnie, podobnie jak identyfikator num i liczba całkowita 10 mogą być używane zamiennie, dzięki czemu można użyć identyfikatora squareIt i wyrażenia fun n -> n * nlambda .

// Make a tuple of values instead of identifiers.
let funAndArgTuple2 = ((fun n -> n * n), 10)

// The following expression applies a squaring function to 10, returns
// 100, and then displays 100.
System.Console.WriteLine((fst funAndArgTuple2)(snd funAndArgTuple2))

Przekazywanie wartości jako argumentu

Jeśli wartość ma stan pierwszej klasy w języku, możesz przekazać ją jako argument do funkcji. Na przykład często przekazujemy liczby całkowite i ciągi jako argumenty. Poniższy kod przedstawia liczby całkowite i ciągi przekazywane jako argumenty w języku 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)

Jeśli funkcje mają stan pierwszej klasy, musisz mieć możliwość przekazania ich jako argumentów w taki sam sposób. Należy pamiętać, że jest to pierwsza cecha funkcji wyższej kolejności.

W poniższym przykładzie funkcja applyIt ma dwa parametry i oparg. Jeśli wysyłasz w funkcji, która ma jeden parametr i op odpowiedni argument dla funkcji do arg, funkcja zwraca wynik zastosowania op do arg. W poniższym przykładzie zarówno argument funkcji, jak i argument liczby całkowitej są wysyłane w taki sam sposób, używając ich nazw.

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

Możliwość wysyłania funkcji jako argumentu do innej funkcji stanowi podstawy typowych abstrakcji w językach programowania funkcjonalnego, takich jak operacje mapowania lub filtrowania. Na przykład operacja mapy jest funkcją o wyższej kolejności, która przechwytuje obliczenia współużytkowane przez funkcje przechodzące przez listę, wykonuje coś do każdego elementu, a następnie zwraca listę wyników. Możesz chcieć zwiększać każdy element na liście liczb całkowitych lub do kwadratu każdego elementu lub zmienić każdy element na liście ciągów na wielkie litery. Podatna na błędy część obliczeń jest cyklicznego procesu, który przechodzi przez listę i tworzy listę wyników do zwrócenia. Ta część jest przechwytywana w funkcji mapowania. Wszystko, co musisz napisać dla określonej aplikacji, to funkcja, którą chcesz zastosować do każdego elementu listy indywidualnie (dodawanie, kwadratura, zmiana wielkości liter). Ta funkcja jest wysyłana jako argument do funkcji mapowania, tak samo jak squareIt w applyIt poprzednim przykładzie.

Język F# udostępnia metody mapy dla większości typów kolekcji, w tym list, tablic i sekwencji. W poniższych przykładach są używane listy. Składnia jest następująca: 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

Aby uzyskać więcej informacji, zobacz Listy.

Zwracanie wartości z wywołania funkcji

Na koniec, jeśli funkcja ma stan pierwszej klasy w języku, musisz mieć możliwość zwrócenia jej jako wartości wywołania funkcji, tak jak zwracasz inne typy, takie jak liczby całkowite i ciągi.

Poniższa funkcja wywołuje zwracane liczby całkowite i wyświetla je.

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

Następujące wywołanie funkcji zwraca ciąg.

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

Następujące wywołanie funkcji zadeklarowane w tekście zwraca wartość logiczną. Wyświetlana wartość to True.

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

Możliwość zwrócenia funkcji jako wartości wywołania funkcji jest drugą cechą funkcji wyższego rzędu. W poniższym przykładzie jest zdefiniowana jako funkcja, checkFor która przyjmuje jeden argument, itemi zwraca nową funkcję jako jej wartość. Zwracana funkcja przyjmuje listę jako argument , lsti wyszukuje element item w lstpliku . Jeśli item jest obecny, funkcja zwraca wartość true. Jeśli item nie jest obecny, funkcja zwraca wartość false. Tak jak w poprzedniej sekcji, poniższy kod używa udostępnionej funkcji list, List.exists, aby wyszukać listę.

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

Poniższy kod używa checkFor metody do utworzenia nowej funkcji, która przyjmuje jeden argument, listę i wyszukuje 7 na liście.

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

W poniższym przykładzie użyto stanu funkcji pierwszej klasy w języku F# do zadeklarowania funkcji , composektóra zwraca kompozycję dwóch argumentów funkcji.

// Function compose takes two arguments. Each argument is a function
// that takes one argument of the same type. The following declaration
// uses lambda expression syntax.
let compose =
    fun op1 op2 ->
        fun n ->
            op1 (op2 n)

// To clarify what you are returning, use a nested let expression:
let compose2 =
    fun op1 op2 ->
        // Use a let expression to build the function that will be returned.
        let funToReturn = fun n ->
                            op1 (op2 n)
        // Then just return it.
        funToReturn

// Or, integrating the more concise syntax:
let compose3 op1 op2 =
    let funToReturn = fun n ->
                        op1 (op2 n)
    funToReturn

Uwaga

Aby uzyskać jeszcze krótszą wersję, zobacz następującą sekcję "Curried Functions".

Poniższy kod wysyła dwie funkcje jako argumenty do compose, z których oba przyjmują jeden argument tego samego typu. Wartość zwracana jest nową funkcją, która jest składem dwóch argumentów funkcji.

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

Uwaga

Język F# udostępnia dwa operatory << i >>, które tworzą funkcje. Na przykład let squareAndDouble2 = doubleIt << squareIt jest odpowiednikiem let squareAndDouble = compose doubleIt squareIt w poprzednim przykładzie.

Poniższy przykład zwracania funkcji jako wartości wywołania funkcji tworzy prostą grę zgadywania. Aby utworzyć grę, wywołaj makeGame metodę z wartością, w której chcesz, aby ktoś odgadł wysłany do elementu .target Wartość zwracana z funkcji jest funkcją makeGame , która przyjmuje jeden argument (zgadywanie) i zgłasza, czy odgadnięcie jest poprawne.

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

Poniższy kod wywołuje makeGamemetodę , wysyłając wartość 7 elementu target. Identyfikator playGame jest powiązany z zwracanym wyrażeniem lambda. W związku z tym jest funkcją, playGame która przyjmuje jako jeden argument wartość .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!

Funkcje curried

Wiele przykładów w poprzedniej sekcji można napisać bardziej zwięzłie, korzystając z niejawnego curryingu w deklaracjach funkcji języka F#. Currying to proces, który przekształca funkcję, która ma więcej niż jeden parametr w serię funkcji osadzonych, z których każdy ma jeden parametr. W języku F# funkcje, które mają więcej niż jeden parametr, są z natury curried. Na przykład z poprzedniej sekcji można napisać, compose jak pokazano w poniższym zwięzłym stylu, z trzema parametrami.

let compose4 op1 op2 n = op1 (op2 n)

Jednak wynik jest funkcją jednego parametru, która zwraca funkcję jednego parametru, który z kolei zwraca inną funkcję jednego parametru, jak pokazano w pliku compose4curried.

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

Dostęp do tej funkcji można uzyskać na kilka sposobów. Każdy z poniższych przykładów zwraca i wyświetla 18. Możesz zastąpić compose4 ciąg ciągiem compose4curried w dowolnym z przykładów.

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

Aby sprawdzić, czy funkcja nadal działa tak jak poprzednio, spróbuj ponownie wykonać oryginalne przypadki testowe.

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)

Uwaga

Można ograniczyć currying, zamykając parametry w krotkach. Aby uzyskać więcej informacji, zobacz "Wzorce parametrów" w temacie Parametry i argumenty.

W poniższym przykładzie użyto niejawnego curryingu, aby napisać krótszą wersję programu makeGame. Szczegóły dotyczące sposobu makeGame konstruowania i zwracania game funkcji są mniej jawne w tym formacie, ale można to sprawdzić przy użyciu oryginalnych przypadków testowych, że wynik jest taki sam.

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'

Aby uzyskać więcej informacji na temat curryingu, zobacz "Częściowa aplikacja argumentów" w usłudze Functions.

Identyfikator i definicja funkcji są zamienne

Nazwa num zmiennej w poprzednich przykładach jest obliczana na liczbę całkowitą 10 i nie jest zaskoczeniem, że gdzie num jest prawidłowa, 10 jest również prawidłowa. To samo dotyczy identyfikatorów funkcji i ich wartości: w dowolnym miejscu, w którym można użyć nazwy funkcji, można użyć wyrażenia lambda, do którego jest powiązana.

Poniższy przykład definiuje Boolean funkcję o nazwie isNegative, a następnie używa nazwy funkcji i definicji funkcji zamiennie. Następne trzy przykłady zwracają i wyświetlają Falseelement .

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)

Aby wykonać ten krok dalej, zastąp wartość applyIt powiązaną z wartością applyIt.

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

Funkcje są wartościami pierwszej klasy w języku F#

Przykłady w poprzednich sekcjach pokazują, że funkcje w języku F# spełniają kryteria bycia wartościami pierwszej klasy w języku F#:

  • Identyfikator można powiązać z definicją funkcji.
let squareIt = fun n -> n * n
  • Funkcję można przechowywać w strukturze danych.
let funTuple2 = ( BMICalculator, fun n -> n * n )
  • Funkcję można przekazać jako argument.
let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]
  • Funkcję można zwrócić jako wartość wywołania funkcji.
let checkFor item =
    let functionToReturn = fun lst ->
                           List.exists (fun a -> a = item) lst
    functionToReturn

Aby uzyskać więcej informacji na temat języka F#, zobacz dokumentację języka F#.

Przykład

opis

Poniższy kod zawiera wszystkie przykłady w tym temacie.

Kod

// ** GIVE THE VALUE A NAME **


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



let squareIt = fun n -> n * n



let squareIt2 n = n * n



// ** STORE THE VALUE IN A DATA STRUCTURE **


// Lists.

// Storing integers and strings.
let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
let stringList = [ "one"; "two"; "three" ]

// You cannot mix types in a list. The following declaration causes a
// type-mismatch compiler error.
//let failedList = [ 5; "six" ]

// In F#, functions can be stored in a list, as long as the functions
// have the same signature.

// Function doubleIt has the same signature as squareIt, declared previously.
//let squareIt = fun n -> n * n
let doubleIt = fun n -> 2 * n

// Functions squareIt and doubleIt can be stored together in a list.
let funList = [ squareIt; doubleIt ]

// Function squareIt cannot be stored in a list together with a function
// that has a different signature, such as the following body mass
// index (BMI) calculator.
let BMICalculator = fun ht wt ->
                    (float wt / float (squareIt ht)) * 703.0

// The following expression causes a type-mismatch compiler error.
//let failedFunList = [ squareIt; BMICalculator ]


// Tuples.

// Integers and strings.
let integerTuple = ( 1, -7 )
let stringTuple = ( "one", "two", "three" )

// A tuple does not require its elements to be of the same type.
let mixedTuple = ( 1, "two", 3.3 )

// Similarly, function elements in tuples can have different signatures.
let funTuple = ( squareIt, BMICalculator )

// Functions can be mixed with integers, strings, and other types in
// a tuple. Identifier num was declared previously.
//let num = 10
let moreMixedTuple = ( num, "two", 3.3, squareIt )



// You can pull a function out of a tuple and apply it. Both squareIt and num
// were defined previously.
let funAndArgTuple = (squareIt, num)

// The following expression applies squareIt to num, returns 100, and
// then displays 100.
System.Console.WriteLine((fst funAndArgTuple)(snd funAndArgTuple))



// Make a list of values instead of identifiers.
let funAndArgTuple2 = ((fun n -> n * n), 10)

// The following expression applies a squaring function to 10, returns
// 100, and then displays 100.
System.Console.WriteLine((fst funAndArgTuple2)(snd funAndArgTuple2))



// ** PASS THE VALUE AS AN ARGUMENT **


// An integer is passed to squareIt. Both squareIt and num are defined in
// previous examples.
//let num = 10
//let squareIt = fun n -> n * n
System.Console.WriteLine(squareIt num)

// String.
// Function repeatString concatenates a string with itself.
let repeatString = fun s -> s + s

// A string is passed to repeatString. HelloHello is returned and displayed.
let greeting = "Hello"
System.Console.WriteLine(repeatString greeting)



// Define the function, again using lambda expression syntax.
let applyIt = fun op arg -> op arg

// Send squareIt for the function, op, and num for the argument you want to
// apply squareIt to, arg. Both squareIt and num are defined in previous
// examples. The result returned and displayed is 100.
System.Console.WriteLine(applyIt squareIt num)

// The following expression shows the concise syntax for the previous function
// definition.
let applyIt2 op arg = op arg
// The following line also displays 100.
System.Console.WriteLine(applyIt2 squareIt num)



// List integerList was defined previously:
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]

// You can send the function argument by name, if an appropriate function
// is available. The following expression uses squareIt.
let squareAll = List.map squareIt integerList

// The following line displays [1; 4; 9; 16; 25; 36; 49]
printfn "%A" squareAll

// Or you can define the action to apply to each list element inline.
// For example, no function that tests for even integers has been defined,
// so the following expression defines the appropriate function inline.
// The function returns true if n is even; otherwise it returns false.
let evenOrNot = List.map (fun n -> n % 2 = 0) integerList

// The following line displays [false; true; false; true; false; true; false]
printfn "%A" evenOrNot



// ** RETURN THE VALUE FROM A FUNCTION CALL **


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


// The following function call returns a string:

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



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



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



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

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

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

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

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



// Function compose takes two arguments. Each argument is a function
// that takes one argument of the same type. The following declaration
// uses lambda expression syntax.
let compose =
    fun op1 op2 ->
        fun n ->
            op1 (op2 n)

// To clarify what you are returning, use a nested let expression:
let compose2 =
    fun op1 op2 ->
        // Use a let expression to build the function that will be returned.
        let funToReturn = fun n ->
                            op1 (op2 n)
        // Then just return it.
        funToReturn

// Or, integrating the more concise syntax:
let compose3 op1 op2 =
    let funToReturn = fun n ->
                        op1 (op2 n)
    funToReturn



// Functions squareIt and doubleIt were defined in a previous example.
let doubleAndSquare = compose squareIt doubleIt
// The following expression doubles 3, squares 6, and returns and
// displays 36.
System.Console.WriteLine(doubleAndSquare 3)

let squareAndDouble = compose doubleIt squareIt
// The following expression squares 3, doubles 9, returns 18, and
// then displays 18.
System.Console.WriteLine(squareAndDouble 3)



let makeGame target =
    // Build a lambda expression that is the function that plays the game.
    let game = fun guess ->
                   if guess = target then
                      System.Console.WriteLine("You win!")
                   else
                      System.Console.WriteLine("Wrong. Try again.")
    // Now just return it.
    game



let playGame = makeGame 7
// Send in some guesses.
playGame 2
playGame 9
playGame 7

// Output:
// Wrong. Try again.
// Wrong. Try again.
// You win!

// The following game specifies a character instead of an integer for target.
let alphaGame = makeGame 'q'
alphaGame 'c'
alphaGame 'r'
alphaGame 'j'
alphaGame 'q'

// Output:
// Wrong. Try again.
// Wrong. Try again.
// Wrong. Try again.
// You win!



// ** CURRIED FUNCTIONS **


let compose4 op1 op2 n = op1 (op2 n)



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



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

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

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



let doubleAndSquare4 = compose4 squareIt doubleIt
// The following expression returns and displays 36.
System.Console.WriteLine(doubleAndSquare4 3)

let squareAndDouble4 = compose4 doubleIt squareIt
// The following expression returns and displays 18.
System.Console.WriteLine(squareAndDouble4 3)



let makeGame2 target guess =
    if guess = target then
       System.Console.WriteLine("You win!")
    else
       System.Console.WriteLine("Wrong. Try again.")

let playGame2 = makeGame2 7
playGame2 2
playGame2 9
playGame2 7

let alphaGame2 = makeGame2 'q'
alphaGame2 'c'
alphaGame2 'r'
alphaGame2 'j'
alphaGame2 'q'



// ** IDENTIFIER AND FUNCTION DEFINITION ARE INTERCHANGEABLE **


let isNegative = fun n -> n < 0

// This example uses the names of the function argument and the integer
// argument. Identifier num is defined in a previous example.
//let num = 10
System.Console.WriteLine(applyIt isNegative num)

// This example substitutes the value that num is bound to for num, and the
// value that isNegative is bound to for isNegative.
System.Console.WriteLine(applyIt (fun n -> n < 0) 10)



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



// ** FUNCTIONS ARE FIRST-CLASS VALUES IN F# **

//let squareIt = fun n -> n * n


let funTuple2 = ( BMICalculator, fun n -> n * n )



let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]


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

Zobacz też