다음을 통해 공유


자동 일반화

F#에서는 형식 유추를 사용하여 함수 및 식의 형식을 평가합니다. 이 항목에서는 F#이 가능한 경우 여러 형식으로 작동하도록 함수의 인수 및 형식을 자동으로 일반화하는 방법을 설명합니다.

자동 일반화

F# 컴파일러는 함수에 대한 형식 유추를 수행할 때 지정된 매개 변수가 제네릭일 수 있는지 여부를 결정합니다. 컴파일러는 각 매개 변수를 검사하고 함수에 해당 매개 변수의 특정 형식에 대한 종속성이 있는지 여부를 확인합니다. 그렇지 않으면 형식이 제네릭으로 유추됩니다.

다음 코드 예제에서는 컴파일러가 제네릭으로 유추하는 함수를 보여 줍니다.

let max a b = if a > b then a else b

형식이 .로 유추됩니다 'a -> 'a -> 'a.

이 형식은 알 수 없는 동일한 형식의 두 인수를 사용하고 동일한 형식의 값을 반환하는 함수임을 나타냅니다. 이전 함수가 제네릭일 수 있는 이유 중 하나는 보다 큰 연산자(>)가 제네릭이기 때문입니다. 보다 큰 연산자에는 서명 'a -> 'a -> bool이 있습니다. 모든 연산자가 제네릭인 것은 아니며 함수의 코드에서 제네릭이 아닌 함수 또는 연산자와 함께 매개 변수 형식을 사용하는 경우 해당 매개 변수 형식을 일반화할 수 없습니다.

max 제네릭이므로 다음 예제와 같이 , 등과 같은 intfloat형식과 함께 사용할 수 있습니다.

let biggestFloat = max 2.0 3.0
let biggestInt = max 2 3

그러나 두 인수는 동일한 형식이어야 합니다. 서명이 'a -> 'a -> 'a아닙니다 'a -> 'b -> 'a. 따라서 다음 코드는 형식이 일치하지 않으므로 오류를 생성합니다.

// Error: type mismatch.
let biggestIntFloat = max 2.0 3

이 함수는 max 보다 큰 연산자를 지원하는 모든 형식에서도 작동합니다. 따라서 다음 코드와 같이 문자열에서도 사용할 수 있습니다.

let testString = max "cab" "cat"

값 제한

컴파일러는 명시적 인수가 있는 전체 함수 정의 및 변경할 수 없는 단순 값에 대해서만 자동 일반화를 수행합니다.

즉, 특정 형식으로 충분히 제한되지 않지만 일반화할 수 없는 코드를 컴파일하려고 하면 컴파일러가 오류를 발생시킵니다. 이 문제에 대한 오류 메시지는 값 제한으로 값의 자동 일반화에 대한 이 제한을 참조합니다.

일반적으로 값 제한 오류는 구문을 제네릭으로 만들지만 컴파일러에 일반화할 정보가 부족하거나 의도치 않게 생성되지 않은 구문에서 충분한 형식 정보를 생략할 때 발생합니다. 값 제한 오류에 대한 해결 방법은 다음 방법 중 하나로 형식 유추 문제를 보다 완벽하게 제한하기 위해 보다 명시적인 정보를 제공하는 것입니다.

  • 값 또는 매개 변수에 명시적 형식 주석을 추가하여 형식을 제네릭이 아닌 형식으로 제한합니다.

  • 함수 컴퍼지션 또는 불완전하게 적용된 curried 함수 인수와 같은 제네릭 함수를 정의하기 위해 생성할 수 없는 구문을 사용하는 경우 함수를 일반 함수 정의로 다시 작성해 보세요.

  • 문제가 너무 복잡해서 일반화할 수 없는 식인 경우 사용되지 않는 추가 매개 변수를 추가하여 함수로 만듭니다.

  • 명시적 제네릭 형식 매개 변수를 추가합니다. 이 옵션은 거의 사용되지 않습니다.

다음 코드 예제에서는 이러한 각 시나리오를 보여 줍니다.

사례 1: 식이 너무 복잡합니다. 이 예제에서는 목록이 counter 의도되었지만 int option ref변경할 수 없는 간단한 값으로 정의되지 않았습니다.

let counter = ref None
// Adding a type annotation fixes the problem:
let counter : int option ref = ref None

사례 2: 제네릭 함수를 정의하기 위해 생성할 수 없는 구문을 사용합니다. 이 예제에서 구문은 함수 인수의 부분 적용을 포함하므로 생성할 수 없습니다.

let maxhash = max << hash
// The following is acceptable because the argument for maxhash is explicit:
let maxhash obj = (max << hash) obj

사례 3: 사용되지 않는 추가 매개 변수 추가 이 식은 일반화에 충분하지 않으므로 컴파일러에서 값 제한 오류를 발생합니다.

let emptyList10 = Array.create 10 []
// Adding an extra (unused) parameter makes it a function, which is generalizable.
let emptyList10 () = Array.create 10 []

사례 4: 형식 매개 변수 추가

let arrayOf10Lists = Array.create 10 []
// Adding a type parameter and type annotation lets you write a generic value.
let arrayOf10Lists<'T> = Array.create 10 ([]:'T list)

마지막 경우 값은 다음과 같이 다양한 형식의 값을 만드는 데 사용할 수 있는 형식 함수가 됩니다.

let intLists = arrayOf10Lists<int>
let floatLists = arrayOf10Lists<float>

참고 항목