F # Quotations - transition to function calls represented by value

I spent several hours trying to deal with F # quotes, but I ran into a small amount of road block. My requirement is to accept simple functions (just integers, +, -, /, *) from the type of discriminatory union and generate an expression tree that will ultimately be used to generate the C code. I know that this is possible with using quotes with "direct" functions.

My problem is that the expression tree seems to end with "Value", and I cannot figure out how to get into that value.

My questions are: is this really possible in this situation? or are there any other approaches worth considering.

type FuncType = | A of (int -> int -> int) | B | C [<ReflectedDefinition>] let add xy = x + y let myFunc1 = A (fun xy -> 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 xy -> x + y @> // generates usable expression tree 
+4
source share
1 answer

Quotes are F # code that is syntactically quoted. This means that if you write something like <@ x @> , the quote will contain only the Value case, indicating that you quoted something that has the specified value. (Variables are automatically replaced with values โ€‹โ€‹if the variable is defined outside of the quote).

You can get a code quote explicitly quoted using <@ .. @> or a function that was marked as ReflectedDefinition and mentioned by name in a quote (e.g. <@ add @> , but not, for example, let f = add in <@ f @> ).

To be able to do what your fragment offers, you also need to save the quotes in FuncType (so that the lambda function you write is also indicated and you can get its body). Sort of:

 type FuncType = | A of Expr<int -> int -> int> | B | C [<ReflectedDefinition>] let add xy = x + y let myFunc1 = A <@ fun xy -> x + y @> let myFunc2 = A <@ add @> let thefunc expr = match expr with | A(x) -> x | _ -> failwith "fail" 

This should work for functions designated as ReflectedDefinition . To extract the body of the function, you need to add something like (you will need to replace the arguments of the function with parameters, but this should give you some idea):

 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" 
+7
source

Source: https://habr.com/ru/post/1339013/


All Articles