2012-04-14 4 views

ответ

7

deepMacroExpandUntil функция была довольно простая утилита, которая только сделал две вещи:

  • Он заменил все вызовы метода ReflectedDefinition атрибута с телом метода
  • Это Уменьшенный лямбда приложения, так (fun x -> x * x) (1+2) станет (1+2)*(1+2)

Это было весьма полезным при написании код обработки котировок, но новые версии F # включают ExprShape активных шаблонов, которые позволяют легко писать обработку котировок вручную.

Чтобы реализовать что-то вроде deepMacroExpandUntil, можно было бы написать что-то вроде:

open Microsoft.FSharp.Quotations 

/// The parameter 'vars' is an immutable map that assigns expressions to variables 
/// (as we recursively process the tree, we replace all known variables) 
let rec expand vars expr = 
    // First recursively process & replace variables 
    let expanded = 
    match expr with 
    // If the variable has an assignment, then replace it with the expression 
    | ExprShape.ShapeVar v when Map.containsKey v vars -> vars.[v] 
    // Apply 'expand' recursively on all sub-expressions 
    | ExprShape.ShapeVar v -> Expr.Var v 
    | Patterns.Call(body, DerivedPatterns.MethodWithReflectedDefinition meth, args) -> 
     let this = match body with Some b -> Expr.Application(meth, b) | _ -> meth 
     let res = Expr.Applications(this, [ for a in args -> [a]]) 
     expand vars res 
    | ExprShape.ShapeLambda(v, expr) -> 
     Expr.Lambda(v, expand vars expr) 
    | ExprShape.ShapeCombination(o, exprs) -> 
     ExprShape.RebuildShapeCombination(o, List.map (expand vars) exprs) 
    // After expanding, try reducing the expression - we can replace 'let' 
    // expressions and applications where the first argument is lambda 
    match expanded with 
    | Patterns.Application(ExprShape.ShapeLambda(v, body), assign) 
    | Patterns.Let(v, assign, body) -> 
     expand (Map.add v (expand vars assign) vars) body 
    | _ -> expanded 

Следующий пример показывает оба аспекта функции - она ​​заменяет функцию foo с его телом, а затем заменяет приложение, так что в итоге с (10 + 2) * (10 + 2):

[<ReflectedDefinition>] 
let foo a = a * a 

expand Map.empty <@ foo (10 + 2) @> 

EDIT: я также отправил образец в F# snippets.

 Смежные вопросы

  • Нет связанных вопросов^_^