Nice programing

F #에서 '인라인'사용

nicepro 2020. 11. 23. 19:58
반응형

F #에서 '인라인'사용


inlineF # 키워드는 내가 예를 들어 C에서 사용했던 것과는 다소 다른 목적을 가지고있는 것 같습니다. 예를 들어, 함수의 유형에 영향을 미치는 것 같습니다 ( "정적으로 확인 된 유형 매개 변수"란 무엇입니까? 모든 F # 유형이 아님). 정적으로 해결 되었습니까?)

inline함수 는 언제 사용해야 합니까?


inline키워드는 함수 정의를 사용하는 인라인 코드에 삽입되는 것을 나타냅니다. 대부분의 경우 이는 함수 유형에 영향을주지 않습니다. 그러나 드물게 .NET에서 컴파일 된 코드 형식으로 표현할 수 없지만 함수가 인라인 될 때 ​​적용 할 수있는 제약 조건이 있기 때문에 좀 더 일반적인 유형의 함수로 이어질 수 있습니다.

이것이 적용되는 주요 사례는 연산자를 사용하는 것입니다.

let add a b = a + b

단형 추론 된 유형을 갖게됩니다 (아마도 int -> int -> int,하지만 float -> float -> float해당 유형에서이 함수를 대신 사용하는 코드가있는 경우 와 같을 수 있습니다 ). 그러나이 함수를 인라인으로 표시하면 F # 컴파일러가 다형성 유형을 유추합니다.

let inline add a b = a + b
// add has type ^a ->  ^b ->  ^c when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)

.NET의 컴파일 된 코드에서이 유형 제약 조건을 첫 번째 클래스 방식으로 인코딩하는 방법은 없습니다. 그러나 F # 컴파일러는 함수를 인라인하는 사이트에서이 제약 조건을 적용하여 모든 연산자 사용이 컴파일 타임에 해결되도록 할 수 있습니다.

유형 매개 변수 ^a, ^b그리고는 ^c, "정적 유형 매개 변수를 해결"하는 인수의 유형이 정적으로 이러한 매개 변수를 사용하는 사이트에 알려진해야한다는 것을 의미합니다. 이는 일반 유형 매개 변수 (예 : 'a, 'b등) 와 대조적입니다 . 여기서 매개 변수는 "나중에 제공되지만 어떤 것이 든 될 수있는 유형"과 같은 것을 의미합니다.


inline함수 는 언제 사용해야 합니까?

inline실제로 키워드 의 가장 가치있는 응용 프로그램은 완전히 최적화 된 단일 코드 조각을 생성하기 위해 함수 인수도 인라인되는 호출 사이트에 고차 함수를 인라인하는 것입니다.

예를 들어, inline다음 fold함수는 5 배 더 빠릅니다.

  let inline fold f a (xs: _ []) =
     let mutable a = a
     for i=0 to xs.Length-1 do
        a <- f a xs.[i]
     a

이것은 inline대부분의 다른 언어에서 수행 하는 것과 거의 유사 하지 않습니다. C ++에서 템플릿 메타 프로그래밍을 사용하여 유사한 효과를 얻을 수 있지만 F #은 inline.NET 메타 데이터를 통해 전달 되기 때문에 컴파일 된 어셈블리간에 인라인 될 수도 있습니다 .


첫 번째 사용 사이트에서만 유형을 평가 (추론)하는 일반 함수와 달리 각 사용 사이트에서 유형을 (재) 평가해야하는 함수를 정의해야하는 경우 인라인을 사용해야합니다. , 그런 다음 그 이후의 다른 모든 곳에서 첫 번째 유추 된 형식 서명을 사용하여 정적으로 형식화 된 것으로 간주됩니다.

인라인의 경우 함수 정의는 효과적으로 일반 / 다형성 인 반면 일반 (인라인이 아닌) 경우 함수는 정적으로 (그리고 종종 암시 적으로) 형식화됩니다.

따라서 인라인을 사용하는 경우 다음 코드 :

let inline add a b = a + b

[<EntryPoint>]
let main args = 

    let one = 1
    let two = 2
    let three = add one two
    // here add has been compiled to take 2 ints and return an int

    let dog = "dog"
    let cat = "cat"
    let dogcat = add dog cat
    // here add has been compiled to take 2 strings and return a string

    printfn "%i" three
    printfn "%s" dogcat   

    0

빌드하고 컴파일하여 다음 출력을 생성합니다.

3  
dogcat

즉, 정수에 더하는 함수와 두 문자열을 연결하는 함수를 모두 생성하는 데 동일한 추가 함수 정의가 사용되었습니다 (실제로 +에 대한 기본 연산자 오버로딩도 인라인을 사용하여 내부에서 수행됨).

이 코드는 add 함수가 더 이상 인라인으로 선언되지 않는다는 점을 제외하면 동일합니다.

let add a b = a + b

[<EntryPoint>]
let main args = 

    let one = 1
    let two = 2
    let three = add one two
    // here add has been compiled to take 2 ints and return an int

    let dog = "dog"
    let cat = "cat"
    let dogcat = add dog cat
    // since add was not declared inline, it cannot be recompiled
    // and so we now have a type mismatch here

    printfn "%i" three
    printfn "%s" dogcat   

    0

컴파일되지 않고 다음 불만 사항에 실패합니다.

    let dogcat = add dog cat
                     ^^^ - This expression was expected to have type int
                           but instead has type string

인라인을 사용하는 것이 적절한 경우에 대한 좋은 예는 두 개의 인수가있는 함수의 인수 적용 순서를 반대로하는 일반 함수를 정의하려는 경우입니다.

let inline flip f x y = f y x

이 질문에 대한 @pad의 답변에서와 같이 Array, List 또는 Seq의 N 번째 요소를 얻기위한 인수 순서가 다릅니다 .


The F# component design guidelines only mention a little about this. My recommendation (that aligns well with what's said there) is:

  • Don't use inline
    • Exception: you might consider using inline when writing mathematical libraries to be consumed by other F# code and you want to write functions that are generic over different numeric data types.

There are lots of other "interesting" uses of inline and static member constraints for "duck-typing" kinds of scenarios that work a bit like C++ templates. My advice is to avoid all of that like the plague.

@kvb's answer goes into more depth about what 'static type constraints' are.

참고URL : https://stackoverflow.com/questions/3754862/use-of-inline-in-f

반응형