함수는 모든 프로그래밍 언어에서 프로그램 실행의 기본 단위입니다. 다른 언어와 마찬가지로 F# 함수에는 이름이 있고, 매개 변수가 있고, 인수를 사용할 수 있으며, 본문이 있습니다. 또한 F#은 함수를 값으로 처리하고, 식에서 명명되지 않은 함수를 사용하고, 함수를 구성하여 새 함수를 구성하고, 커리 함수를 구성하며, 함수 인수의 부분 적용을 통해 함수의 암시적 정의와 같은 함수 프로그래밍 구문을 지원합니다.
키워드를 사용하여 함수를 let 정의하거나, 함수가 재귀적 let rec 이면 키워드 조합을 정의합니다.
문법
// Non-recursive function definition.
let [inline] function-name parameter-list [: return-type ] = function-body
// Recursive function definition.
let rec function-name parameter-list = recursive-function-body
비고
함수 이름은 함수를 나타내는 식별자입니다. 매개 변수 목록은 공백으로 구분된 연속 매개 변수로 구성됩니다. 매개 변수 섹션에 설명된 대로 각 매개 변수에 대해 명시적 형식을 지정할 수 있습니다. 특정 인수 형식을 지정하지 않으면 컴파일러는 함수 본문에서 형식을 유추하려고 시도합니다. 함수 본문은 식으로 구성됩니다. 함수 본문을 구성하는 식은 일반적으로 반환 값인 최종 식에서 절정에 이르는 여러 식으로 구성된 복합 식입니다. return-type은 콜론 뒤에 형식이 오는 형식이며 선택 사항입니다. 반환 값의 형식을 명시적으로 지정하지 않으면 컴파일러가 최종 식에서 반환 형식을 결정합니다.
간단한 함수 정의는 다음과 유사합니다.
let f x = x + 1
앞의 예제에서 함수 이름은 f이고, 인수는 x이고 그 형식은 int이며, 함수 본문은 x + 1이고, 반환 값의 형식은 int입니다.
함수를 표시 inline할 수 있습니다. 자세한 inline내용은 인라인 함수를 참조하세요.
범위
모듈 범위 이외의 범위 수준에서 값이나 함수 이름을 다시 사용하는 것은 오류가 아닙니다. 이름을 다시 사용하는 경우 나중에 선언된 이름은 이전에 선언된 이름을 숨깁니다. 그러나 모듈의 최상위 범위에서 이름은 고유해야 합니다. 예를 들어 다음 코드는 모듈 범위에 나타날 때 오류를 생성하지만 함수 내에 나타날 때는 그렇지 않습니다.
let list1 = [ 1; 2; 3 ]
// Error: duplicate definition.
let list1 = []
let function1 () =
let list1 = [ 1; 2; 3 ]
let list1 = []
list1
그러나 다음 코드는 모든 범위 수준에서 허용됩니다.
let list1 = [ 1; 2; 3 ]
let sumPlus x =
// OK: inner list1 hides the outer list1.
let list1 = [ 1; 5; 10 ]
x + List.sum list1
매개 변수
매개 변수의 이름은 함수 이름 앞에 나열됩니다. 다음 예제와 같이 매개 변수의 형식을 지정할 수 있습니다.
let f (x: int) = x + 1
형식을 지정하는 경우 매개 변수의 이름을 따르고 콜론으로 이름과 구분됩니다. 매개 변수의 형식을 생략하면 매개 변수 형식이 컴파일러에서 유추됩니다. 예를 들어 다음 함수 정의에서는 1이 형식이므로 인수 x 가 형식 int 으로 유추됩니다 int.
let f x = x + 1
그러나 컴파일러는 함수를 가능한 한 제네릭으로 만들려고 시도합니다. 예를 들어 다음 코드를 확인합니다.
let f x = (x, x)
함수는 모든 형식의 한 인수에서 튜플을 만듭니다. 형식이 지정되지 않았으므로 함수를 인수 형식과 함께 사용할 수 있습니다. 자세한 내용은 자동 일반화를 참조하세요.
함수 본문
함수 본문에는 지역 변수 및 함수의 정의가 포함될 수 있습니다. 이러한 변수 및 함수는 현재 함수 본문의 범위에 있지만 외부에는 없습니다. 다음 예제와 같이 들여쓰기를 사용하여 정의가 함수 본문에 있음을 나타내야 합니다.
let cylinderVolume radius length =
// Define a local value pi.
let pi = 3.14159
length * pi * radius * radius
자세한 내용은 코드 서식 지침 및 자세한 구문을 참조하세요.
반환 값
컴파일러는 함수 본문의 최종 식을 사용하여 반환 값 및 형식을 결정합니다. 컴파일러는 이전 식의 최종 식 형식을 유추할 수 있습니다. 이전 섹션에 표시된 함수 cylinderVolume에서 형식 pi 은 리터럴 3.14159 형식에서 결정됩니다 float. 컴파일러는 형식을 pi 사용하여 식 length * pi * radius * radius 형식을 결정합니다 float. 따라서 함수의 전체 반환 형식은 .입니다 float.
반환 형식을 명시적으로 지정하려면 다음과 같이 코드를 작성합니다.
let cylinderVolume radius length : float =
// Define a local value pi.
let pi = 3.14159
length * pi * radius * radius
위에서 작성한 코드로 컴파일러는 전체 함수에 부동 소수 자릿수 를 적용합니다. 매개 변수 형식에도 적용하려는 경우 다음 코드를 사용합니다.
let cylinderVolume (radius: float) (length: float) : float
함수 호출
함수 이름 뒤에 공백을 지정한 다음 공백으로 구분된 인수를 지정하여 함수를 호출합니다. 예를 들어 , function cylinderVolume 을 호출하고 value vol에 결과를 할당하려면 다음 코드를 작성합니다.
let vol = cylinderVolume 2.0 3.0
인수의 부분 적용
지정된 인수 수보다 적은 수의 인수를 제공하는 경우 나머지 인수를 예상하는 새 함수를 만듭니다. 이 인수 처리 방법은 커리라고 하며 F#과 같은 기능 프로그래밍 언어의 특징입니다. 예를 들어 두 가지 크기의 파이프로 작업한다고 가정해 보겠습니다. 하나는 반지름 이 2.0 이고 다른 크기는 반경 이 3.0입니다. 다음과 같이 파이프 볼륨을 결정하는 함수를 만들 수 있습니다.
let smallPipeRadius = 2.0
let bigPipeRadius = 3.0
// These define functions that take the length as a remaining
// argument:
let smallPipeVolume = cylinderVolume smallPipeRadius
let bigPipeVolume = cylinderVolume bigPipeRadius
그런 다음 두 가지 크기의 다양한 파이프 길이에 필요한 최종 인수를 제공합니다.
let length1 = 30.0
let length2 = 40.0
let smallPipeVol1 = smallPipeVolume length1
let smallPipeVol2 = smallPipeVolume length2
let bigPipeVol1 = bigPipeVolume length1
let bigPipeVol2 = bigPipeVolume length2
재귀 함수
재귀 함수는 자신을 호출하는 함수입니다. let 키워드 다음에 rec 키워드를 지정해야 합니다. 함수 호출을 호출하는 것처럼 함수 본문 내에서 재귀 함수를 호출합니다. 다음 재귀 함수는 n번째 피보나치 번호를 계산합니다. 피보나치 숫자 시퀀스는 고대부터 알려져 있으며, 각 연속 숫자가 시퀀스에서 이전 두 숫자의 합계인 시퀀스입니다.
let rec fib n =
if n < 2 then 1 else fib (n - 1) + fib (n - 2)
일부 재귀 함수는 프로그램 스택을 오버플로하거나 비상 재귀, 누적기 및 연속의 사용과 같은 특수 기술을 주의하여 작성하지 않으면 비효율적으로 수행할 수 있습니다.
함수 값
F#에서 모든 함수는 값으로 간주됩니다. 실제로 함수 값이라고 합니다. 함수는 값이므로 다른 함수 또는 값이 사용되는 다른 컨텍스트에서 인수로 사용할 수 있습니다. 다음은 함수 값을 인수로 사용하는 함수의 예입니다.
let apply1 (transform: int -> int) y = transform y
토큰을 사용하여 함수 값의 형식을 -> 지정합니다. 이 토큰의 왼쪽에는 인수의 형식이 있고 오른쪽에는 반환 값이 있습니다. 이전 예제 apply1 에서는 함수를 인수로 사용하는 함수 transform 입니다. 여기서 transform 정수는 다른 정수로 반환됩니다. 다음 코드는 사용하는 apply1방법을 보여줍니다.
let increment x = x + 1
let result1 = apply1 increment 100
result 값은 이전 코드가 실행된 후 101이 됩니다.
다음 예제와 같이 여러 인수가 연속 -> 토큰으로 구분됩니다.
let apply2 (f: int -> int -> int) x y = f x y
let mul x y = x * y
let result2 = apply2 mul 10 20
결과는 200입니다.
람다 식
람다 식은 명명되지 않은 함수입니다. 이전 예제에서는 명명된 함수 증분 및 mul을 정의하는 대신 다음과 같이 람다 식을 사용할 수 있습니다.
let result3 = apply1 (fun x -> x + 1) 100
let result4 = apply2 (fun x y -> x * y) 10 20
키워드를 사용하여 람다 식을 정의합니다 fun . 람다 식은 토큰 -> 대신 = 함수 본문에서 인수 목록을 분리하는 데 사용된다는 점을 제외하고 함수 정의와 유사합니다. 일반 함수 정의에서와 같이 인수 형식을 명시적으로 유추하거나 지정할 수 있으며, 람다 식의 반환 형식은 본문의 마지막 식 형식에서 유추됩니다. 자세한 내용은 람다 식: 키 fun 워드를 참조하세요.
파이프라인
파이프 연산자 |> F#에서 데이터를 처리할 때 광범위하게 사용됩니다. 이 연산자를 사용하면 유연한 방식으로 함수의 "파이프라인"을 설정할 수 있습니다. 파이프라인을 사용하면 함수 호출을 연속 작업으로 함께 연결할 수 있습니다.
let result = 100 |> function1 |> function2
다음 샘플에서는 이러한 연산자를 사용하여 간단한 기능 파이프라인을 빌드하는 방법을 안내합니다.
/// Square the odd values of the input and add one, using F# pipe operators.
let squareAndAddOdd values =
values |> List.filter (fun x -> x % 2 <> 0) |> List.map (fun x -> x * x + 1)
let numbers = [ 1; 2; 3; 4; 5 ]
let result = squareAndAddOdd numbers
결과는 [2; 10; 26]입니다. 이전 샘플에서는 목록 처리 함수를 사용하여 파이프라인을 빌드할 때 함수를 사용하여 데이터를 처리하는 방법을 보여 줍니다. 파이프라인 연산자 자체는 다음과 같이 F# 코어 라이브러리에 정의됩니다.
let (|>) x f = f x
함수 컴퍼지션
F#의 함수는 다른 함수에서 구성할 수 있습니다. 두 functions function1 과 function2 의 컴퍼지션은 function1 의 애플리케이션과 function2의 애플리케이션을 나타내는 또 다른 함수입니다.
let function1 x = x + 1
let function2 x = x * 2
let h = function1 >> function2
let result5 = h 100
결과는 202입니다.
컴퍼지션 연산 >> 자는 두 개의 함수를 사용하고 함수를 반환합니다. 반면 파이프라인 연산 |> 자는 값과 함수를 사용하고 값을 반환합니다. 다음 코드 예제에서는 함수 서명과 사용량의 차이를 보여 줌으로써 파이프라인과 컴퍼지션 연산자의 차이를 보여 줍니다.
// Function composition and pipeline operators compared.
let addOne x = x + 1
let timesTwo x = 2 * x
// Composition operator
// ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3
let Compose2 = addOne >> timesTwo
// Backward composition operator
// ( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
let Compose1 = addOne << timesTwo
// Result is 5
let result1 = Compose1 2
// Result is 6
let result2 = Compose2 2
// Pipelining
// Pipeline operator
// ( |> ) : 'T1 -> ('T1 -> 'U) -> 'U
let Pipeline2 x = addOne x |> timesTwo
// Backward pipeline operator
// ( <| ) : ('T -> 'U) -> 'T -> 'U
let Pipeline1 x = addOne <| timesTwo x
// Result is 5
let result3 = Pipeline1 2
// Result is 6
let result4 = Pipeline2 2
함수 오버로드
형식의 메서드를 오버로드할 수 있지만 함수는 오버로드할 수 없습니다. 자세한 내용은 메서드를 참조 하세요.
참고하십시오
.NET