정적으로 확인된 형식 매개 변수
정적으로 확인된 형식 매개 변수는 런타임이 아닌 컴파일 시간에 실제 형식으로 대체되는 형식 매개 변수입니다.
구문
'type-parameter
F# 버전 7.0까지는 다음 구문을 사용해야 했습니다.
^type-parameter
설명
F#에는 두 가지 종류의 형식 매개 변수가 있습니다. 그중 하나는 일반 제네릭 형식 매개 변수입니다. 이 매개 변수는 다른 .NET 언어의 제네릭 형식 매개 변수와 동일합니다. 또 다른 하나는 정적으로 확인되며, 인라인 함수에서만 사용할 수 있습니다.
정적으로 확인된 형식 매개 변수는 주로 멤버 제약 조건과 결합하여 유용합니다. 멤버 제약 조건은 형식 인수를 사용하기 위한 조건으로 하나 이상의 특정 멤버 포함을 지정하는 제약 조건입니다. 일반 제네릭 형식 매개 변수를 사용하여 이러한 종류의 제약 조건을 만들 수 있는 방법은 없습니다.
다음 표에는 이 두 종류의 형식 매개 변수 간의 유사점과 차이점이 요약되어 있습니다.
기능 | 일반 | 정적으로 확인됨 |
---|---|---|
확인 시간 | 실행 시간 | 컴파일 시간 |
멤버 제약 조건 | 멤버 제약 조건과 함께 사용할 수 없습니다. | 멤버 제약 조건과 함께 사용할 수 있습니다. |
코드 생성 | 일반 제네릭 형식 매개 변수가 있는 형식(또는 메서드)은 단일한 제네릭 형식 또는 메서드를 생성합니다. | 필요한 각 형식에 대해 하나씩으로, 형식 및 메서드의 여러 인스턴스화가 생성됩니다. |
형식에 사용 | 형식에 사용할 수 있습니다. | 형식에서 사용할 수 없습니다. |
인라인 함수와 함께 사용 | 일반 제네릭 형식 매개 변수를 사용하여 인라인 함수를 매개 변수화할 수 없습니다. 입력이 완전히 제네릭이 아닌 경우 F# 컴파일러는 입력을 특수화하거나, 특수화할 옵션이 없는 경우 오류를 발생합니다. | 정적으로 확인된 형식 매개 변수는 인라인이 아닌 함수 또는 메서드에는 사용할 수 없습니다. |
많은 F# 코어 라이브러리 함수, 특히 연산자는 정적으로 확인된 형식 매개 변수를 가지고 있습니다. 이러한 함수와 연산자는 인라인이며 숫자 계산에 효율적인 코드를 생성할 수 있게 합니다.
연산자를 사용하거나 정적으로 확인된 형식 매개 변수가 있는 다른 함수를 사용하는 인라인 메서드 및 함수는 정적으로 확인된 형식 매개 변수를 자체적으로 사용할 수도 있습니다. 종종 형식 유추는 이러한 인라인 함수를 유추하여 정적으로 확인된 형식 매개 변수를 갖습니다. 다음 예에서는 정적으로 확인된 형식 매개 변수를 갖도록 유추되는 연산자 정의를 보여줍니다.
let inline (+@) x y = x + x * y
// Call that uses int.
printfn "%d" (1 +@ 1)
// Call that uses float.
printfn "%f" (1.0 +@ 0.5)
확인된 (+@)
형식은 (+)
와 (*)
둘 다의 사용을 기반으로 하며, 둘 다 형식 유추가 정적으로 확인된 형식 매개 변수에 대한 멤버 제약 조건을 유추합니다. F# 인터프리터에 표시된 것처럼 확인된 형식은 다음과 같습니다.
'a -> 'c -> 'd
when ('a or 'b) : (static member ( + ) : 'a * 'b -> 'd) and
('a or 'c) : (static member ( * ) : 'a * 'c -> 'b)
출력은 다음과 같습니다.
2
1.500000
다음 예에서는 메서드 및 정적 메서드를 사용하여 SRTP를 사용하는 방법을 보여줍니다.
type Record =
{ Number: int }
member this.Double() = { Number = this.Number * 2 }
static member Zero() = { Number = 0 }
let inline double<'a when 'a:(member Double: unit -> 'a)> (x: 'a) = x.Double()
let inline zero<'a when 'a:(static member Zero: unit -> 'a)> () = 'a.Zero()
let r: Record = zero ()
let doubleR = double r
F# 7.0부터는 아래 예시와 같이 제약 조건을 반복하는 대신 'a.Zero()
를 사용할 수 있습니다.
또한 F# 4.1부터는 정적으로 확인된 형식 매개 변수 서명에서 구체적인 형식 이름을 지정할 수 있습니다. 이전 버전의 언어에서는 형식 이름이 컴파일러에서 유추되었지만 서명에 지정할 수 없었습니다. F# 4.1 기준으로 정적으로 확인된 형식 매개 변수 서명에서 구체적인 형식 이름을 지정할 수 있습니다. 다음은 예시입니다(이 예에서는 '
사용을 위한 간소화가 지원되지 않으므로 ^
를 계속 사용해야 합니다).
let inline konst x _ = x
type CFunctor() =
static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a
static member inline fmap (f: ^a -> ^b, a: ^a option) =
match a with
| None -> None
| Some x -> Some (f x)
// default implementation of replace
static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) =
((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f))
// call overridden replace if present
static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) =
(^b : (static member replace: ^a * ^b -> ^c) (a, f))
let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) =
((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f))
// Note the concrete type 'CFunctor' specified in the signature
let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or ^b): (static member replace: ^a * ^b -> ^a0) =
replace_instance<CFunctor, _, _, _> (a, f)
참고 항목
.NET