2017-01-26 75 views
6

Powiedzmy mam ten cytat typu Quotations.Expr<(int -> int -> int)>częściowe zastosowanie F # Notowań

<@ fun x y -> x + y @> 

Chcę utworzyć funkcję fun reduce x expr że kiedy nazywa się reduce 1 expr będzie zasadniczo otrzymując

<@ fun y -> 1 + y @> 

tj chcę częściowo zastosuj wycenę, aby wyprodukować inną ofertę.

Jestem pewien, że jest to wykonalne, czy ktoś ma jakieś myśli? Czy próbowano już wcześniej? Nie mogę niczego znaleźć.

Również nie jestem bardzo zaznajomiony z LISP-em, ale czy jest to zasadniczo podobne do tego, co mogę osiągnąć za pomocą makr LISP?

AKTUALIZACJA: Obniżając cytat, chciałbym ocenić części, które można ocenić w wynikowym drzewie wyrażeń.

Na przykład: reduce true <@ fun b x y -> if b then x + y else x - [email protected]> powinien spowodować <@ fun x y -> x + y @>.

+0

Chociaż odpowiedź @kvb dostarcza użytecznych wskazówek dla uproszczenia wyrażeń, I polecam zadać inne konkretne pytanie. TAK naprawdę błyszczy na małe, samodzielne pytania i odpowiedzi. – CaringDev

+0

Pojmowany @CaringDev – tejas

Odpowiedz

4

Jeśli wiesz, że Twój cytat jest postaci fun x ... to proste:

let subst (v:'a) (Patterns.Lambda(x,b) : Expr<'a->'b>) = 
    b.Substitute(fun x' -> if x = x' then Some (Expr.Value v) else None) 
    |> Expr.Cast<'b> 

subst 1 <@ fun x y -> x + y @> 

Jeśli dodatkowo chcemy uprościć wyrażenia, a następnie istnieje kilka nieco podchwytliwe pytania trzeba odpowiedzieć:

  • Czy interesują Cię efekty uboczne? Jeśli zacznę od <@ fun x y -> printfn "%i" x @> i zastępuję w 1 dla x, jaka jest uproszczona wersja <@ fun y -> printfn "%i" 1 @>? To powinno wydrukować 1 za każdym razem, gdy zostanie wywołany, ale jeśli nie wiesz z wyprzedzeniem, które wyrażenia mogą powodować efekty uboczne, prawie nigdy nie uprościsz niczego. Jeśli to zignorujesz (zakładając, że żadna ekspresja nie spowoduje efektów ubocznych), wtedy rzeczy stają się znacznie prostsze kosztem wierności.
  • Co naprawdę oznacza uproszczenie? Powiedzmy, że dostaję <@ fun y -> y + 1 @> po zamianie. Czy to jest dobre czy złe, aby uprościć to do odpowiednika let f y = y+1 in <@ f @>? Jest to zdecydowanie "prostsze", ponieważ jest to trywialne wyrażenie zawierające tylko wartość, ale wartość jest teraz funkcją nieprzezroczystą. Co jeśli mam <@ fun y -> 1 + (fun z -> z) y @>? Czy można w prosty sposób uprościć funkcję wewnętrzną do wartości lub zła?

Jeśli możemy ignorować skutków ubocznych i nie zawsze chcą zastąpić funkcję o wartości, a następnie można zdefiniować funkcję uproszczenia tak:

let reduce (e:Expr<'a>) : Expr<'a> = 
    let rec helper : Expr -> Expr = function 
    | e when e.GetFreeVars() |> Seq.isEmpty && not (Reflection.FSharpType.IsFunction e.Type) -> // no free variables, and won't produce a function value 
     Expr.Value(Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation e, e.Type) 
    | ExprShape.ShapeLambda(v, e) -> Expr.Lambda(v, helper e) // simplify body 
    | ExprShape.ShapeCombination(o, es) -> // simplify each subexpression 
     ExprShape.RebuildShapeCombination(o, es |> List.map helper) 
    | ExprShape.ShapeVar v -> Expr.Var v 

    helper e |> Expr.Cast 

pamiętać, że ta wciąż nie może uprość rzecz tak, jak chcesz; na przykład <@ (fun x (y:int) -> x) 1 @> nie zostanie uproszczony, chociaż będzie to <@ (fun x -> x) 1 @>.

+0

Nie oceniłoby części, które można ocenić poprawnie? Na przykład: 'fun bxy -> if b następnie x + y else x -y' Po wywołaniu' subst true xy expr' powinno dać 'fun xy -> x + y' – tejas

+0

@tejas - zobacz edycję – kvb

+0

Dzięki @kvb, dałeś mi wystarczająco dużo, aby kontynuować. – tejas

2

Łączenie jest wygodnym sposobem osadzania cytaty w cudzysłowie:

let reduce x expr = 
    <@ (%expr) x @> 

reduce ma typ 'a -> Expr<('a -> 'b)> -> Expr<'b>

Zastosowanie:

let q = <@ fun x y -> x + y @> 
let r = reduce 1 q // Expr<int -> int> 
let s = reduce 2 <| reduce 3 q // Expr<int> 
let t = reduce "world" <@ sprintf "Hello %s" @> // Expr<string> 
+0

Łączenie jest dobrą rzeczą, o której należy wiedzieć, ale nie sądzę, że to odpowiedź na pytanie (nawet przed edycją) - "zmniejszenie 1 q" daje w wyniku odpowiednik '<@ (zabawa xy -> x + y) 1 @> ', nie' <@ fun y -> 1 + y @> 'zgodnie z życzeniem. Chociaż są one semantycznie równoważne, w przypadku cytowań często troszczy się również o strukturę syntaktyczną. – kvb

+0

@kvb Absolutnie! Powinno to zapewnić jedynie szerszy obraz, a IMO pasuje do "Częściowego zastosowania ..." i "... zasadniczo ...". Ktoś, kto natknie się na to pytanie, może jeszcze uznać moją odpowiedź za przydatną, więc na razie zostawię ją tutaj. – CaringDev