2009-11-07 4 views
1

나는 가지고있는 사용자 정의 데이터 유형에서 작동하는 F #에서 Linq 표현식 트리를 생성 중입니다. 이 유형은 일반적인 산술 연산자가 오버로드 된 매우 단순한 구분 된 합집합입니다. 하지만 정확한 이유 때문에 정확한 linload 표현식 노드를 만들 수 없다. 문제는, 내가 전에이 작업을 했었다고 맹세하지만, 내가 뭘 바꾸 었는지 알 수 없다.Linq 표현식 트리를 사용하여 연산자 오버로딩을 수행 할 수 없습니다.

문제를 나타내는 작은 코드 샘플을 첨부하겠습니다. 아래 데이터 유형에는 Addition 연산자가 오버로드되어 있습니다. 오버로드 된 연산자를 사용하면 매력처럼 작동하지만 Expression.Add (lhs, rhs)를 사용하여 추가 식 트리 노드를 만들려고하면 시스템이 Add 연산에 대한 오버로드를 찾을 수 없다는 예외를 던집니다.

누구에게 내가 뭘 잘못하고 있는지 아이디어가 있습니까?

module Main = 
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) = 
     let clhs = Expression.Constant(lhs, typeof<DataType.DataCarrier>) 
     let crhs = Expression.Constant(rhs, typeof<DataType.DataCarrier>) 
     Expression.Add(clhs, crhs) 

또 다른 옵션은 다음과 같습니다

open System.Linq.Expressions 

module DataType = 
    exception NotImplementedYet of string 

    type DataCarrier = 
     | ScalarCarrier of float 
     | VectorCarrier of float array 

     member this.Add(other) = 
      match (this, other) with 
      | ScalarCarrier(x), ScalarCarrier(y) -> ScalarCarrier(x + y) 
      | VectorCarrier(u), VectorCarrier(v) -> 
       VectorCarrier(Array.map2 (fun x y -> x + y) u v) 
      | _,_ -> raise (NotImplementedYet("No go!")) 

     static member (+) (lhs:DataCarrier, rhs) = 
      lhs.Add(rhs) 

module Main = 
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) = 
     let clhs = Expression.Constant(lhs) 
     let crhs = Expression.Constant(rhs) 
     Expression.Add(clhs, crhs) 

(* no problems with this one *) 
printf "Testing operator overloading: %A" (DataType.ScalarCarrier(1.0) 
              + DataType.ScalarCarrier(2.0)) 
(* this throws an exception *) 
printf "Testing expr construction %A" (Main.createAddOp 
             (DataType.ScalarCarrier(1.0)) 
             (DataType.ScalarCarrier(2.0))) 

답변

3

하나의 솔루션이 명시 적으로 (자신의 실행시의 형태 DataType.DataCarrier.ScalarCarrier 대신 그들에게 정적 유형 DataType.DataCarrier을 제공) 식의 피연산자를 입력하는 것입니다, 리 카드를 주셔서 감사합니다 명시 적으로 더하기 연산자를 사용하여 전달해야합니다.

module Main = 
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) = 
     let clhs = Expression.Constant(lhs) 
     let crhs = Expression.Constant(rhs) 
     Expression.Add(clhs, crhs, typeof<DataType.DataCarrier>.GetMethod("op_Addition")) 

원래 코드가 작동하지 않는다는 것에 놀랐습니다. 표현식 트리가 관련 추가 연산자를 찾는 방식에 한계가있는 것으로 나타납니다 (즉, Linq는 런타임 유형의 피연산자에 대해서만 연산자를 찾습니다).

+0

환상적이었고, 나는 실제로 해결 방법이 없다고 생각했습니다. 방금 스트레스를 많이 덜어 줬어! +1 나는 이것이 F #의 10 월 CTP 이전에 사용되었다고 생각한다. 내가 시험해 볼게. – Rickard