정적으로 확인된 형식 매개 변수가 있는 인라인 함수에는 특정 이름과 서명을 가진 멤버가 필요할 수 있습니다. F# 11.2를 사용하면 형식이 다른 어셈블리에서 가져온 경우에도 범위 내 확장 멤버가 해당 요구 사항을 충족할 수 있습니다.
이 기능을 사용하여 특정 형식에 대한 어댑터와 제네릭 알고리즘을 구분합니다. 이러한 형식을 래핑하거나 명목 인터페이스를 추가할 필요가 없습니다.
Note
.NET 11.0.100 SDK에서 컴파일러가 확장을 확인하는 위치를 사용하도록 설정합니다<LangVersion>preview</LangVersion>. 계획된 기능 밴드에 대한 F# 11.2 언어 설정을 참조하세요. 경로 및 매핑 예제에서는 F# 11.0 라이브러리 및 미리 보기 소비자를 사용합니다. 컴파일 라이브러리 및 소비자를 참조하세요.
공유 알고리즘에 대한 속성 조정
다음 애플리케이션 코드는 두 개의 기존 프레임워크 형식으로 표시되는 경로를 측정합니다. 두 경로의 길이 8는 다음과 같습니다.
open System.Numerics
open Structural.Adapters
open Structural.Algorithms
let complexRoute =
[ Complex(0.0, 0.0); Complex(3.0, 4.0); Complex(6.0, 4.0) ]
let vectorRoute =
[ Vector2(0.0f, 0.0f); Vector2(3.0f, 4.0f); Vector2(6.0f, 4.0f) ]
printn (pathLength complexRoute) // 8
printn (pathLength vectorRoute) // 8
라이브러리 원본이 정의하고 Structural.Algorithms.Structural.Adapters 어댑터는 네이티브 API가 다른 형식에 동일한 좌표 속성을 노출합니다.
type System.Numerics.Complex with
member point.Coordinates = point.Real, point.Imaginary
type System.Numerics.Vector2 with
member point.Coordinates = float point.X, float point.Y
알고리즘은 부동 소수점 값 쌍을 반환하는 속성을 요청 Coordinates 합니다.
let inline coordinates (point: ^Point) : float * float =
(^Point : (member Coordinates: float * float) point)
let inline pathLength (points: ^Point list) =
points
|> List.pairwise
|> List.sumBy (fun (a, b) ->
let ax, ay = coordinates a
let bx, by = coordinates b
let dx, dy = bx - ax, by - ay
sqrt (dx * dx + dy * dy))
각 구체적인 호출에서 컴파일러는 제약 조건의 미러 서버 Coordinates 라는 멤버를 선택합니다. 인라인 알고리즘은 내장 속성 또는 확장 속성을 허용합니다. 빈 경로와 단일 지점 경로의 길이는 0입니다.
컬렉션 형식 간에 작업 공유
확장 제약 조건은 정적 멤버도 지원합니다. 라이브러리의 Structural.Adapters 모듈은 기존 List.map 및 Option.map 함수를 사용하여 어댑터를 정의합니다.
type List<'T> with
static member Map(source: 'T list, mapping: 'T -> 'U) : 'U list =
List.map mapping source
type Option<'T> with
static member Map(source: 'T option, mapping: 'T -> 'U) : 'U option =
Option.map mapping source
라이브러리의 Structural.Algorithms 모듈에서 전체 입력 형식에 대한 멤버를 요청 Map 합니다.
let inline map (mapping: 'T -> 'U) (source: ^Input) : ^Output =
(^Input :
(static member Map: ^Input * ('T -> 'U) -> ^Output)
(source, mapping))
그런 다음, 애플리케이션은 변환을 공유하고, 요소 형식을 변경하고, 중첩된 컬렉션에 대한 매핑을 작성할 수 있습니다.
let inline cleanNames values =
map (fun (name: string) -> name.Trim().ToUpperInvariant()) values
let batch: string list = cleanNames [ " Ada "; " grace " ]
let optional: string option = cleanNames (Some " linus ")
let missing: string option = cleanNames (None: string option)
let lengths: int list = map String.length batch
let nested: int option list = map (map String.length) [ Some "abc"; None ]
printfn "%A; %A; %A" batch optional missing
printfn "%A; %A" lengths nested
// ["ADA"; "GRACE"]; Some "LINUS"; None
// [3; 5]; [Some 3; None]
컴파일러는 인터페이스 또는 매핑 법률이 아닌 멤버 이름과 형식을 확인합니다. 더 높은 종류의 다형성이 아닙니다. 다음과 같은 F<_>컨테이너 생성자를 나타내는 매개 변수가 없습니다.
연산자 확장
연산자는 동일한 메커니즘을 사용할 수 있습니다. 예를 들어 목록 및 옵션에 대한 매핑 연산자를 정의합니다.
type List<'T> with
static member (|>>) (source: 'T list, mapping: 'T -> 'U) =
List.map mapping source
type Option<'T> with
static member (|>>) (source: 'T option, mapping: 'T -> 'U) =
Option.map mapping source
let inline (|>>) (source: ^Input) (mapping: 'T -> 'U) : ^Output =
(^Input :
(static member (|>>): ^Input * ('T -> 'U) -> ^Output)
(source, mapping))
소비자가 연산자를 열고 StructuralOperators 사용합니다.
open StructuralOperators
let incremented: int list = [1; 2; 3] |>> ((+) 10)
let length: int option = Some "hello" |>> String.length
// [11; 12; 13] and Some 5
기본 제공 기본 연산자 솔루션은 일치 형식에 대한 우선 순위를 유지합니다. 확장은 임의의 혼합 숫자 확대를 제공하거나 모든 기본 제공 연산자를 대체하지 않습니다.
F# 11.0 모드는 FS1215를 사용하는 일반 확장 연산자 선언을 수락할 수 있지만 SRTP 솔루션으로 사용할 수는 없습니다. 연산자 프로젝트는 미리 보기를 사용합니다.
튜플 연산자 및 컨텍스트
관찰 및 독립적으로 누적된 결과 쌍의 컬렉션은 동일한 조합 프로토콜에 참여할 수 있습니다. 다음 소비자는 라이브러리의 어댑터를 연 후 제네릭 알고리즘을 정의합니다.
open Composition.Adapters
open Composition.Algorithms
let inline combineAll (batches: ^T list) : ^T =
List.reduce (++) batches
let observations = combineAll [["temperature"]; ["pressure"; "humidity"]]
let summary = combineAll [(2, ["temperature"]); (3, ["pressure"; "humidity"])]
printfn "%A" observations
printfn "%A" summary
// ["temperature"; "pressure"; "humidity"]
// (5, ["temperature"; "pressure"; "humidity"])
이러한 라이브러리 확장은 연산자에게 정수, 목록 및 쌍에 대한 의미를 부여합니다.
type System.Int32 with
static member (++) (left: int, right: int) = left + right
type List<'T> with
static member (++) (left: 'T list, right: 'T list) = left @ right
type ('T1 * 'T2) with
static member inline (++) ((a, b), (c, d)) = (a ++ c, b ++ d)
combineAll 을 사용 List.reduce하므로 비어 있지 않은 목록이 필요합니다. 이 작업은 목록 순서를 유지합니다. 컴파일러는 결합성을 적용하거나 빈 입력에 대한 ID를 제공하지 않습니다.
네이티브 헤더 및 type ('T1 * 'T2) withtype struct ('T1 * 'T2) with CLR 참조 및 값 튜플을 확장합니다. 둘 다 F# 11.2 기능이며 2~7개의 요소를 지원합니다. 더 큰 헤더는 FS3915를 생성합니다.
튜플은 값과 함께 컨텍스트를 전달할 수도 있습니다. 다음 연산자는 컨텍스트 함수를 적용하는 동안 내역을 추가합니다.
let priced =
(["catalogue price"], fun units -> decimal units * 12m)
<*> (["validated quantity"], 3)
printfn "%A" priced
// (["catalogue price"; "validated quantity"], 36M)
type ('Context * 'Value) with
static member inline (<*>) ((before, mapping), (after, value)) =
(before ++ after, mapping value)
type struct ('Context * 'Value) with
static member inline (<*>) (struct (before, mapping), struct (after, value)) =
struct (before ++ after, mapping value)
튜플 점 인스턴스 호출 및 네이티브 함수 형식 헤더(예: type ('a -> 'b) with 지원되지 않음).
컴퍼지션 라이브러리와 소비자는 모두 미리 보기를 사용합니다.
combineAll 소비자 유지: 해당 감소를 내보내면 튜플++용 FS0193을 생성할 수 있습니다. 별도의 경로 및 매핑 예제는 알고리즘을 내보냅니다.
반환 방향 생성
컨테이너에 일반 값을 도입하는 작업의 경우 출력 형식은 생성해야 하는 멤버를 식별할 수 있습니다.
type List<'T> with
static member Return(value: 'T) : 'T list = [value]
type Option<'T> with
static member Return(value: 'T) : 'T option = Some value
let inline singleton (value: 'T) : ^Output =
(^Output : (static member Return: 'T -> ^Output) value)
let oneBatch: string list = singleton "ready"
let oneOptional: string option = singleton "ready"
// ["ready"] and Some "ready"
소비자의 결과 주석은 출력 형식의 Return 확장을 선택합니다. 입력만으로는 컨테이너를 선택할 수 없습니다.
각 컨테이너는 자체 멤버를 제공합니다. 단일 형식의 반환 전용 오버로드의 경우 별도의 AllowOverloadOnReturnType 특성을 사용합니다.
라이브러리 및 소비자 컴파일
언어 설정은 참조를 통해 전이적으로 적용되지 않고 프로젝트별로 적용됩니다. 다음 행렬에서는 F# 11.2 기능에 대한 .NET 11.0.100 SDK 설정을 사용합니다.
| 라이브러리 구현 | 소비자 사용 | 미리 보기 요구 사항 |
|---|---|---|
| 네이티브 튜플 확장 헤더를 선언합니다. | 확장 연산자를 확인합니다. | 둘 다 미리 보기가 필요합니다. 새 헤더 구문 자체는 미리 보기입니다. |
| 일반 확장을 정의하고 해결되지 않은 인라인 멤버 제약 조건을 내보냅니다. | 확장이 해당 제약 조건을 해결하는 구체적인 형식을 제공합니다. | 소비자는 미리 보기가 필요합니다. 라이브러리는 F# 11.0을 사용할 수 있습니다. |
| 내부적으로 확장 제약 조건을 해결하고 일반 또는 이미 확인된 인라인 API를 노출합니다. | 추가 확장 확인 없이 해당 API를 호출합니다. | 라이브러리에는 미리 보기가 필요합니다. 소비자는 F# 11.0을 사용할 수 있습니다. |
| 확장을 해결하고 소비자가 확장을 통해 확인하는 제약 조건을 내보냅니다. | 나머지 제약 조건을 해결합니다. | 둘 다 미리 보기가 필요합니다. |
경로 및 매핑 라이브러리는 소비자에서 사용합니다preview11.0. 소비자 디렉터리에서 지원되는 F# 11 SDK를 사용하여 실행 dotnet run 합니다.
어셈블리의 확장 범위
종속 인라인 함수를 정의하기 전에 공용 확장을 사용하고 해당 모듈을 엽니다. 가져온 미해결 제약 조건의 경우 소비자의 어댑터도 엽니다. 생산자의 open 선언은 전송되지 않습니다. 이미 확인된 API는 소비자가 어댑터를 다시 열 필요가 없습니다.
유추 및 서명
F# 11.2 해상도는 F# 11.0 모드가 이전에 선택한 항목을 지연합니다. 수신기로 정의된 인라인 도우미를 고려합니다.DateTime
let inline shift (date: System.DateTime) offset = date + offset
F# 11.0 모드에서 이 양식은 유추 DateTime -> TimeSpan -> DateTime할 수 있습니다. F# 11.2 확장 해상도를 사용하도록 설정하면 에 대한 (DateTime or ^Offset) : (static member (+) : DateTime * ^Offset -> ^Result)제약 조건을 유지할 수 있습니다. 그런 다음 소비자는 다른 오프셋 형식에 대한 공용 범위 내 확장을 선택할 수 있습니다.
소비자는 F# 11.0 라이브러리에서 손실된 일반성을 복구할 수 없습니다. 내보낸 서명을 확인합니다. 생산자는 F# 11.2 유추를 사용하도록 설정해야 할 수도 있습니다.
미리 보기 제한 사항 및 문제 해결
- FS0001 또는 FS0193의 경우 언어 설정, 공용 표시 유형 및 어댑터 범위를 확인합니다.
- 이후 생산자 파일이 경로 예제를
Complex확인하면 코드 생성이 FS0971Undefined value 'get_Coordinates'로 실패할 수 있습니다. 해당 정의를 사용하여 또는 별도의 소비자에 해당 해상도를 유지합니다. - 경쟁 어댑터는 멤버 선택을 모호하게 만들 수 있습니다.
또한, 다음을 참조하세요.
.NET