假设我有Quotations.Expr<(int -> int -> int)>
<@ fun x y -> x + y @>
我想创建一个函数fun reduce x expr
,当调用reduce 1 expr
时基本上会产生
<@ fun y -> 1 + y @>
即。我想部分应用报价来产生另一个报价。
我确信这是可行的,有没有人有任何想法?以前是否曾尝试过?似乎找不到任何东西。
此外,我对LISP不是很熟悉 - 但这与我用LISP宏实现的基本相似吗?
更新: 在减少报价的同时,我想评估可以在结果表达式树中评估的零件。
例如:reduce true <@ fun b x y -> if b then x + y else x - y@>
应该会产生<@ fun x y -> x + y @>
。
答案 0 :(得分:4)
如果您知道自己的报价格式为import 'rxjs/add/operator/withLatestFrom';
var campaignSelected$ = this.store.select(
store => store.appDb.uiState.campaign.campaignSelected
);
var campaignsList$ = this.store.select(
store => store.msDatabase.sdk.table_campaigns
);
return campaignSelected$.withLatestFrom(
campaignsList$,
(campaignId, campaigns) => { ... }
);
,那么很简单:
fun x ...
如果您还想简化表达式,那么您需要回答一些棘手的问题:
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 @>
开始,并在<@ fun x y -> printfn "%i" x @>
中替换为1
,那么x
的简化版本是什么?这应该在每次调用时打印出<@ fun y -> printfn "%i" 1 @>
,但除非您提前知道哪些表达式可能会导致副作用,否则您几乎不会简化任何事情。如果你忽略这一点(假设没有表达会导致副作用)那么事情变得更加简单,但代价是保真度。1
。然后,将此简化为等同于<@ fun y -> y + 1 @>
是好还是坏?这绝对是更简单的&#34;因为它只是一个包含一个值的普通表达式,但该值现在是一个不透明的函数。如果我有let f y = y+1 in <@ f @>
怎么办?是否可以将内部函数简化为值,还是不好?如果我们可以忽略副作用并且我们不想用一个值替换一个函数,那么你可以定义一个这样的简化函数:
<@ fun y -> 1 + (fun z -> z) y @>
请注意,这仍然可能不像您所希望的那样简化;例如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
将不会被简化,但<@ (fun x (y:int) -> x) 1 @>
将是。
答案 1 :(得分:2)
拼接是在引号中嵌入引号的便捷方式:
let reduce x expr =
<@ (%expr) x @>
reduce
的类型为'a -> Expr<('a -> 'b)> -> Expr<'b>
用法:
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>