2015-10-15 6 views
2

Я использую цитаты из F # для создания функции, которая проверяет, удовлетворяет ли один вход любому из нескольких случаев. То есть, функция whos body - это что-то вроде ... || ... || ..., где число || s определяется во время выполнения. Несколько упрощена, что я сейчасСтроительная квартира котируемая лямбда

let vals = [|1..3|] 
let currentfilter = 
    vals 
    |> Array.fold (fun acc i -> 
     <@ fun j -> (%acc) j || j = i @>) 
     <@ fun _ -> false @> 

, который генерирует дерево

val currentfilter : Expr<(int -> bool)> = 
    Lambda (j, 
     IfThenElse (Application (Lambda (j, 
             IfThenElse (Application (Lambda (j, 
                      IfThenElse (Application (Lambda (_arg1, 
                              Value (false)), 
                            j), 
                         Value (true), 
                         Call (None, 
                          op_Equality, 
                          [j, 
                          Value (1)]))), 
                    j), 
                Value (true), 
                Call (None, op_Equality, 
                  [j, Value (2)]))), j), 
        Value (true), Call (None, op_Equality, [j, Value (3)]))) 

Оптимально, что я хочу, чтобы генерировать больше похож

Lambda (j, 
     IfThenElse (IfThenElse (Call (None, op_Equality, [j, Value (1)]), 
           Value (true), 
           Call (None, op_Equality, [j, Value (2)])), 
        Value (true), Call (None, op_Equality, [j, Value (3)]))) 

(Это был сгенерирован <@ fun j -> j = 1 || j = 2 || j = 3 @>)

Есть ли простой способ сглаживания первого выражения, чтобы сделать его похожим на второе?

ответ

4

Вы можете написать код так, чтобы он не возвращает цитируемый функцию, но вместо этого возвращает функцию, которая генерирует цитаты, когда данный вход:

let vals = [|1..3|] 

let currentfilter = 
    vals |> Array.fold (fun acc i -> 
     fun j -> <@ %(acc j) || %j = i @>) 
     (fun _ -> <@ false @>) 

в складку:

  • Начальное значение - это функция, которая возвращает false выражение
  • Агрегация составляет выражение gen до сих пор с выражением, которое сравнивает вход (заданный как цитату) со значением i.

Теперь, чтобы создать полную цитируемую функцию, мы хотели бы написать что-то вроде этого:

<@ fun j -> %(currentfilter <@ j @>) @> 

К сожалению, это не работает - потому что F # компилятор немного строг здесь и не напишем код, где переменная j может скрыть свою область действия (вполне разумная, но неудачная).

Таким образом, вместо этого, вы можете написать это, построив цитату вручную:

open Microsoft.FSharp.Quotations 

let v = Var.Global("j", typeof<int>) 
Expr.Lambda(v, currentfilter (Expr.Cast(Expr.Var(v)))) 
+0

Briliant. Спасибо. Это точно то, что я спросил. – torbonde