F # Quotations - переход к вызовам функций, представленных значением - PullRequest
4 голосов
/ 09 февраля 2011

Я потратил несколько часов, пытаясь справиться с цитатами F #, но я столкнулся с некоторым препятствием.Мое требование состоит в том, чтобы взять простые функции (только целые числа, +, -, /, *) из различимого типа объединения и сгенерировать дерево выражений, которое в конечном итоге будет использоваться для генерации кода на языке Си.Я знаю, что это возможно, используя цитаты с «прямыми» функциями.

Моя проблема в том, что дерево выражений, похоже, оканчивается на «Значение», и я не могу понять, как перейти к этому значению.

Мои вопросы: возможно ли это в этой ситуации?или есть другие подходы, которые стоит рассмотреть.

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

1 Ответ

7 голосов
/ 09 февраля 2011

Кавычки представляют код F #, который был цитирован синтаксически .Это означает, что если вы напишите что-то вроде <@ x @>, цитата будет содержать только Value регистр, указывающий, что вы цитировали что-то, имеющее указанное значение.(Переменные автоматически заменяются значениями, если переменная определена вне кавычек).

Вы можете получить только цитату кода, который был явно заключен в кавычки с использованием <@ .. @>, или функции, помеченной как ReflectedDefinitionи упоминается имя в кавычках (например, <@ add @>, но не, например, let f = add in <@ f @>).

Чтобы иметь возможность делать то, что предлагает ваш фрагмент кода, вам также нужно хранить цитаты в вашем FuncType (чтобы лямбда-функция, которую вы пишете, также заключалась в кавычки и вы могли получить ее тело).Примерно так:

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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...