0

F # 컴파일러는 다른 유형이 이후에 호출되는 함수를 통해 다른 경로를 암시하는 함수를 호출하여 코드 경로를 구분할 수 있습니까?F # 컴파일러는 currying을 사용하여 유형에 따라 코드 경로를 구분할 수 있습니까?

다음과 같은 구분 된 합집합을 고려하십시오. 이론적으로 서로 다른 종류 2 가지 가능성이있다 :

type Choice = 
    | Halve 
    | Double 

우리는 이러한 경우 중 일부에 대한 몇 가지 특정 기능이 있다고 가정 : 2 개 별도의 코드 경로를 제공

let halve value = value/2.0 
let divide value = value * 2.0 

그리고이 기능 유형에 따라 하

let inner param value = 
    match param with 
    | Choice.Halve -> halve value 
    | Choice.Double -> divide value 

let outer param value = 
    let internalVariable = 
     match param with 
     | Choice.Halve -> "halving" 
     | Choice.Double -> "doubling" 
    inner param value 


[<EntryPoint>] 
let main argv = 
    printf "%g\n" (outer Choice.Halve 4.0) 
    let doubler = outer Choice.Double 
    printf "%g\n" (doubler 6.0) 

이등분 더블 따라서 별도의 코드 경로이며, 우리는 수 : 일부 param의 (잔부 FS 파일을 완료) 그들을 두 개의 분리 된 기능으로 작성했습니다.

이론적으로 말하자면, 두 가지 다른 기능이 있다고 말합니다. Choice.Halve 또는 Choice.Double 유형 (예 : doubler) 중 첫 번째 매개 변수를 카레하면 해당 유형에 맞는 함수가 있고 컴파일러는 나중의 분기를 최적화 할 수 있어야합니다.

그런 경우입니까?

일리노이를 살펴보면 이러한 최적화는 볼 수 없지만 JITted 일 가능성이 있습니다. 동료는 분기 예측이 그러한 최적화를 필요로하지 않는다고 제안합니다.

불필요한 가지를 피하여 구조를 뒤집고 divide/halve 함수를 전달하는 유일한 방법은?

- 편집 -

존 팔머는 inline를 추가 할 것을 제안했다, 그래서 나는 그것을 시도하고 outer에 대해 다음과 최적화 된 IL을 가지고 :

IL_0001: ldarg.0 
IL_0002: call instance int32 Program/Choice::get_Tag() 
IL_0007: ldc.i4.1 
IL_0008: bne.un.s IL_0016 

IL_000a: ldarg.1 
IL_000b: ldc.r8 2 
IL_0014: mul 
IL_0015: ret 

IL_0016: ldarg.1 
IL_0017: ldc.r8 2 
IL_0020: div 
IL_0021: ret 

그러나, doubler 카레의 명백한 최적화가 없다 함수는 main에 있습니다 - 따라서 uncurried 함수는 최적화되었지만 카레 함수는 최적화되지 않았습니다. ,

let inner param = 
    match param with 
    | Choice.Halve -> (fun value -> halve value) 
    | Choice.Double -> (fun value -> divide value) 

이 기능

원래 기능과 같은 방식으로 사용할 수 있습니다

+1

어떤 함수에 대해서도'inline'을 사용해 보셨습니까? –

답변

2

나는 컴파일러는 자동으로이 작업을 수행 할 것이라고 생각하지 않는다, 그러나이 명시 적으로 구현하는, 그래서 당신은 당신의 코드를 작성할 수 있습니다 예 inner 1.0 2.0이지만 단 하나의 인수로 호출하면 실제로 본문의 첫 번째 부분을 실행하고 대/소문자 본문에 만들어진 함수를 반환합니다.

+0

그리고'(fun value -> halfval value)'는'halve'를 작성하는 η 확장 된 방법 일뿐입니다. – kvb

+0

그래서 반값으로 바꾼다면 '나누기'로 '나누기'와 '내부'의 인수 목록에서 값을 제거하면 별도의 경로가 생겨 최적화 될 것입니다. 왜 그런 차이가 있습니까? –