F#Quotations - 遍历由Value表示的函数调用

Jim*_*mmy 4 f#

我花了几个小时试图掌握F#Quotations,但我遇到了一些路障.我的要求是从一个有区别的联合类型中取出简单的函数(只是整数,+, - ,/,*)并生成一个最终将用于生成C代码的表达式树.我知道这可以使用带有"直接"功能的报价.

我的问题是表达式树似乎以"值"终止,我无法弄清楚如何遍历该值.

我的问题是在这种情况下这是否真的可行?还是有其他值得考虑的方法.

type FuncType = 
| A of (int -> int -> int)
| B
| C

[<ReflectedDefinition>]
let add x y = x + y


let myFunc1 = A (fun x y -> x + y )
let myFunc2 = A add 

let thefunc expr = 
    match expr with
    | A(x) ->
        <@ x @>
    | _ ->
        failwith "fail"

printfn "%A" (thefunc myFunc1) // prints "Value (<fun:myFunc1@14>)"
printfn "%A" (thefunc myFunc2) // prints "Value (<fun:myFunc2@15>)"
printfn "%A" <@ fun x y -> x + y @> // generates usable expression tree
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 7

引号表示语法引用的F#代码.这意味着,如果您编写类似的内容<@ x @>,引号将仅包含Value指定您引用具有指定值的内容的大小写.(如果变量在报价之外定义,变量将自动替换为值).

您只能获取使用明确引用的代码<@ .. @>或引用的函数的引用,ReflectedDefinition并在引用中通过名称引用(例如<@ add @>但不是例如let f = add in <@ f @>).

为了能够做你的代码片段建议的内容,你需要在你的内容中存储引号FuncType(这样你编写的lambda函数也会被引用,你可以得到它的正文).就像是:

type FuncType = 
  | A of Expr<int -> int -> int>
  | B | C

[<ReflectedDefinition>]
let add x y = x + y

let myFunc1 = A <@ fun x y -> x + y @>
let myFunc2 = A <@ add @>

let thefunc expr = 
    match expr with
    | A(x) -> x
    | _ -> failwith "fail"
Run Code Online (Sandbox Code Playgroud)

这应该适用于标记为的功能ReflectedDefinition.要提取函数的主体,你需要添加类似的东西(你需要用函数的参数替换参数,但这应该给你一些想法):

match expr with
| Lambdas(_, body) -> 
    match body with 
    | Call(_, mi, _) when Expr.TryGetReflectedDefinition(mi) <> None ->
      let func = Expr.TryGetReflectedDefinition(mi)
      match func with 
      | Some(Lambdas(_, body)) ->
          // 'body' is the quotation of the body
      | _ -> failwith "Not supported function"
    | _ -> failwith "Not supported function"
| _ -> failwith "Not supported expression"
Run Code Online (Sandbox Code Playgroud)