2012-10-30 3 views
8

이러한 기능은 정확히 동일합니까? 다시 말하면, 1과 2 구문은 마지막 구문에 대한 편리한 약어일까요? 아니면 이론적으로나 실제적으로 어떤 차이가 있습니까? 그렇다면 무엇입니까?이러한 기능의 차이점

let f3 = (fun a -> (fun b -> a + b))

let f2 a = (fun b -> a + b)

let f1 a b = a + b

그들은 f1 5, f2 5f3 5는 예를 들어, 동일한 값을 반환하는 것, 나에게 동일하게 보인다. 그냥 내가 여기에 잘못된 가정을하고있는 것은 아닙니다. 다른 말로하면 나는 지식 기반의 답변을 원하지만 "그래, 나는 그들이 똑같다고 믿는다"고 말하는 것은 아니다.

+2

[내 대답은 여기] (http://stackoverflow.com/questions/2175940/int-int-int-what-dis-meis-mean-in-f/2176428#2176428)를 확인하면 차이 –

+0

나는 대답에서 세 번째 케이스를 포함하는 질문을 보완했다. – hyde

답변

8

귀하의 가정은 정확합니다.이 경우 기능은 완전히 동일합니다.

생성 된 IL 코드를 검사하여 (Craig에서 보여준 것처럼) 볼 수 있으며 F # 컴파일러에서 유추 한 유형을 보면이를 볼 수도 있습니다. 두 경우 모두 int -> int -> int이 표시됩니다. F # 언어는 int을 반환하고 int -> int을 반환하는 함수로 간주하지만 효율성을 위해 실제로는 여러 인수가있는 메서드로 컴파일됩니다.

let .. = 다음에 바로 fun을 쓰면 컴파일러에서이를 표준 기능으로 변환합니다.

let f1 a b = printfn "hi"; a + b 
let f2 a = printfn "hi"; (fun b -> a + b) 

은 이제 두 가지 기능이 매우 다른 두 번째 인쇄는 "안녕하세요"당신은 단지 그것을 줄 때 때문에 :이 기능을 반환하기 전에 몇 가지 계산을 할 경우, 당신은 약간 다른 코드를 작성할 수 있습니다

> let f = f2 1;; 
hi      // The body is called, prints 
val f : (int -> int) // and returns function 

> f 2;;     // This runs the body of 'fun' 
val it : int = 3  // which performs the additiion 

당신은 f1를 사용하여 동일한 코드를 작성할 수 있지만, 첫 번째 명령은 단지 새로운 함수를 작성하고 두 번째 명령이 "안녕하세요"인쇄합니다 : 하나의 인수 (다음 당신이 호출 할 수있는 기능을 반환) 추가를하십시오.

이 경우 f2에 대해 생성 된 IL 코드는 달라집니다. (FSharpFunc<int, int> 유형) 함수를 반환하는 함수입니다. F #이 표시하는 형식도 달라서 int -> int -> int 대신 int -> (int -> int)이됩니다. 이 두 가지 유형의 값을 정확히 같은 방식으로 사용할 수 있지만, 단일 인수를 주면 첫 번째 효과가 발생할 수 있음을 알 수 있습니다.

5

여기 f1의 IL있어 :

.method public static int32 f1(int32 a, 
           int32 b) cil managed 
{ 
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = (01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00) 
    // Code size  5 (0x5) 
    .maxstack 4 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: ldarg.1 
    IL_0003: add 
    IL_0004: ret 
} // end of method Program::f1 

... 그리고 대한 F2 :

.method public static int32 f2(int32 a, 
           int32 b) cil managed 
{ 
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = (01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00) 
    // Code size  5 (0x5) 
    .maxstack 4 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: ldarg.1 
    IL_0003: add 
    IL_0004: ret 
} // end of method Program::f2 

당신이 볼 수 있듯이, 그것은, 그래서 그래, 그들은 같은 본질적으로 동일한 것입니다.

+0

일부 테스트 케이스에서 동일한 바이트 코드를 생성하는 것이 실제로 관련이 있습니까? 즉, 함수를 사용하는 방법에 관계없이 함수에서 마지막으로 "실제"메서드를 호출하게됩니다. – hyde

+0

네, 그렇습니다. Tomas가 이유를 설명했습니다. –

5

두 기능이 동일합니다. 그들은 문법적 당으로 간주 될 수있다.

let f = fun a -> fun b -> a + b 

실용적인 작은 차이가있다.f1은 함수가 값을 반환하고 f2은 클로저를 반환하고 차례대로 값을 생성한다는 점을 강조합니다. f2의 사용은 연결자를 만드는 데 조금 더 매력적입니다. parser combinators.

참고로 F #에서 기능에 대한 동일성이 없으므로 f1 5f2 5은 다른 값이지만 동일한 입력에 동일한 출력을 생성합니다.

+0

+1 나는 이것이 F #을 이해하는 데 유용한 대답이고 좋은 방법이라고 생각합니다. 엄밀히 말하면 F # (및 다른 ML 언어)은'let'과'fun'를 사용하여 정의 된 함수를 다르게 취급하기 때문에'let fab = ... '의 문법적인 당류입니다 (let을 사용하여 정의 된 함수는 generic 일 수 있고 function '재미 '는 사용할 수 없다). 이 코드는 body가 다른 코드없이'fun'를 포함하고있는 한'let f a b = ...'를 사용하는 것처럼 다루어집니다. –