함수를 고급 값으로 상승(F#)

함수형 프로그래밍 언어의 정의상 특징은 함수를 고급 상태로 상승시킨다는 점입니다. 함수를 사용하면 다른 기본 제공 형식의 값으로 수행할 수 있는 모든 작업을 상대적으로 적은 노력으로 수행할 수 있습니다.

고급 상태인지 측정하는 일반적인 기준은 다음과 같습니다.

  • 식별자를 값에 바인딩할 수 있는지 여부. 즉, 식별자에 이름을 지정할 수 있는지 여부

  • 목록 같은 데이터 구조에 값을 저장할 수 있는지 여부

  • 함수 호출에서 값을 인수로 전달할 수 있는지 여부

  • 함수 호출의 값으로 함수를 반환할 수 있는지 여부

마지막 두 가지 측정 기준은 고차 연산 또는 고차 함수라고 하는 항목을 정의합니다. 고차 함수는 함수를 인수로 받고 함수 호출의 값으로 함수를 반환합니다. 이러한 연산은 매핑 함수 및 함수 컴퍼지션 같은 함수형 프로그래밍의 핵심적 기능을 지원합니다.

값에 이름 지정

함수가 고급 값일 경우 정수, 문자열 및 기타 기본 제공 형식에 이름을 지정하듯이 이 값에 이름을 지정할 수 있어야 합니다. 함수형 프로그래밍 문서에서는 이름을 지정하는 것을 가리켜 식별자를 값에 바인딩한다고 합니다. F#에서는 let 식을 사용하여 let <identifier> = <value>와 같이 값에 이름을 바인딩합니다. 다음 코드에서는 두 가지 예제를 보여 줍니다.

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

함수 이름은 쉽게 지정할 수 있습니다. 다음 예제에서는 squareIt 식별자를 람다 식 fun n -> n * n에 바인딩하여 squareIt라는 함수를 정의합니다. 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로 사용하고 lst에서 item을 검색합니다. 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을 반환하고 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 역시 당연히 올바릅니다. 이는 함수 식별자와 해당 값의 경우에도 마찬가지입니다. 함수 이름이 사용될 수 있는 위치에서는 이 이름이 바인딩되는 람다 식 역시 사용될 수 있습니다.

다음 예제에서는 isNegative라는 Boolean 함수를 정의한 다음 함수 이름과 함수 정의를 서로 바꿔 사용합니다. 다음 세 가지 예제에서는 모두 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#의 함수가 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# 언어 참조을 참조하십시오.

예제

설명

다음 코드에는 이 항목의 모든 예제가 포함되어 있습니다.

코드

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