2014-04-18 4 views
13

다음은 C#으로 수행 할 수있는 작업 -F # lambda를 사용하여 Linq 표현식 트리를 어떻게 만듭니 까?

var two = 2; 
System.Linq.Expressions.Expression<System.Func<int, int>> expr = x => x * two; 
expr.Compile().Invoke(4); // returns 8 

내가 F 번호의 정확한 동등을하고 싶습니다.

let two = 2 
let expr = (fun x -> x * two) : System.Linq.Expressions.Expression<System.Func<int, int>> 
expr.Compile().Invoke(4) // desired to return 8 

을 아마도 예상, 컴파일 다음과 같은 오류와 함께 라인이 실패 - - 당신이 F 번호 견적을 사용하지 않도록하려는 이유를 잘 모르겠어요

"This function takes too many arguments, or is used in a context where a function is not expected." 
let expr = (fun x -> x * two) : System.Linq.Expressions.Expression<System.Func<int, int>> 
      ^^^^^^^^^^^^^^^^ 

답변

15

여기에 내가했지만, 컴파일되지 않은 것입니다 - 커버 아래에, 그들은 C# expression tree와 거의 똑같습니다. F #에서 expression tree를 만들고 싶다면, 컴파일러는 어떤 경우에도 커버 아래의 인용문을 사용하게됩니다 ...

어쨌든, 당신은 명시 적으로 작성하지 않고도이 작업을 수행 할 수 있습니다.왜냐하면 컴파일러는 함수에 인수로 전달 될 때 자동으로 함수를 인용 할 수 있기 때문입니다. 그래서 당신은 할 수 있습니다 :

type Expr = 
    static member Quote(e:Expression<System.Func<int, int>>) = e 

let two = 2 
let expr = Expr.Quote(fun x -> x * two) 
expr.Compile().Invoke(4) // desired to return 8 

편집 : 그러나,이 정말 C#을 식 트리로 변환 호출에 싸서 F 번호 인용에 컴파일합니다. 따라서 결국 쓴 것처럼 똑같은 결과를 얻게됩니다.

open Microsoft.FSharp.Linq.RuntimeHelpers 

let two = 2 
let expr = 
    <@ System.Func<_, _>(fun x -> x * two) @> 
    |> LeafExpressionConverter.QuotationToExpression 
    |> unbox<Expression<Func<int, int>>> 
expr.Compile().Invoke(4) // desired to return 8 
+0

답장을 보내 주셔서 감사합니다. 그것은 작지만 작은 비트로 보이지만 멋지 네요. 그러나 질문에 답하기 위해 AFAIK는 어휘 환경 (예 :'two')에서 변수를 포착 할 수 없기 때문에 코드 인용을 피하고 싶었습니다. 변하기 쉬운). 비록 그것이 틀린 경우에, 그러나 저를 정정하십시오! –

+1

두 경우 모두 동일하게 작동합니다. 로컬'let' 바운드 변수는 따옴표에 포착되지 않습니다. 변수의 값만 포함됩니다. 모듈에 의해 공개 된 공개 변수는 참조로 캡처됩니다 (속성 게터로). –

+0

편집까지 따라야합니다. 표현 트리 자체가 주변 컨텍스트에서 가져온 참조를 변경하는 경우 예상대로 작동하지 않습니다. 내가 사용하려고하는 람다 중 일부는 더 넓은 프로그램 상태로 돌연변이를 일으킬 수 있습니다. –