我花了几个小时试图掌握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
答案 0 :(得分:7)
引号表示引用语法的F#代码。这意味着,如果您编写类似<@ x @>
的内容,则引号将仅包含Value
个案例,指定您引用具有指定值的内容。 (如果变量在报价之外定义,变量将自动替换为值。)
您只能引用使用<@ .. @>
明确引用的代码或标记为ReflectedDefinition
且在引文中由 name 引用的函数的引用(例如<@ 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"
这也适用于标记为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"