2011-05-16 67 views
1

有沒有辦法從Expr提取參數?F# - 從Expr提取選項

一個例子:

let hasStringOption (e:Expr<string option>) = 
    let myOption : string option = ..some code to get the string option from e 

我該如何獲得Exprstring option並將其分配給myOption

+0

它取決於,如果你有<@ Some(f x)@>,你想評估函數調用嗎?如果是這樣,請使用wmeyer提及的Eval;否則,斯蒂芬的解決方案就是要走的路。 – Laurent 2011-05-17 15:05:36

回答

4

在你的榜樣,string option代表表達返回類型,所以表達式本身可以是任意複雜的,需要某種像PowerPack中的評價策略作爲@wmeyer顯示。

但是,如果你確實有一個string option表達您可以使用標準庫報價活動模式和反射來實現自己的評估策略(這裏顯示的通用選項):

module P = Microsoft.FSharp.Quotations.Patterns 

let extract (expr:Expr<'a option>) = 
    match expr with 
    | P.NewUnionCase (uci, args) -> 
     if uci.Name = "Some" then 
      match args.Head with 
      | P.Value(value, ty) -> Some(value :?> 'a) 
     else 
      None:('a option) 

let example1 = extract <@ None:int option @> 
let example2 = extract <@ Some("hello world") @> 

而事實上,這樣的方法可能是您自己的一種策略,用於使用反射和活動模式遞歸評估任意表達式,而不是PowerPack緩慢而有限的中間LINQ策略。

+0

感謝您的整齊的功能:) - 但是..爲什麼你使用'None :('選項)'?什麼是:所有關於? – ebb 2011-05-18 09:05:52

+0

嗨@ebb,不客氣。 ':('選項)'None :('選項)的一部分'只是一個類型註釋,我最初用它來幫助編譯器推斷'extract'的返回類型。但是由於Some(value:?>'a)'分支就足夠線索了(我首先寫了None分支),結果是沒有必要的。另一方面,爲了幫助編譯器推斷'example1'的最終類型,':int option' *是必需的。但它也可以通過在example1上放置類型註釋來完成:'let example1:int option = extract <@ None @>' – 2011-05-18 12:18:49

0

可悲(或不),你無法評估F#報價。 F#PowerPack具有編譯LINQ表達式(可以評估)的引用的有限能力。

+1

我已經實現了一個自定義的基於反射的報價評估器,它現在是2.0.0版本以前的Unquote的一部分,http://code.google.com/p/unquote/。我認爲它比PowerPack的評估程序快50倍,並且它還支持更多的表達式。 – 2011-07-13 02:07:31

3

有了引用,你可以做FSharp.PowerPack.Linq.dll

open Microsoft.FSharp.Quotations 
    open Microsoft.FSharp.Linq.QuotationEvaluation 


    let hasStringOption (e:Expr<string option>) = 
     let myOption : string option = e.Eval() 
     myOption.IsSome 

    printfn "%A" (hasStringOption <@ Some "hello" @>) 
    printfn "%A" (hasStringOption <@ None @>) 

然而,據報道,這是相當緩慢的,並使用LINQ表達式作爲一箇中間步驟。