F# 使用计算表达式组合引用函数
我环顾四周,努力寻找答案;我肯定有一个显而易见的答案,但我就是找不到;或者我遇到了引用的限制,当与计算表达式一起使用时,我无法通过引用 基本上,我想使用一个计算F#工作流处理一个引用的lambda,定义如下。当尝试将这些工作流组合在一起时会出现问题。理想情况下,我希望使用let将工作流实例组合在一起!语法。我有点天真的尝试如下:F# 使用计算表达式组合引用函数,f#,quotations,computation-expression,F#,Quotations,Computation Expression,我环顾四周,努力寻找答案;我肯定有一个显而易见的答案,但我就是找不到;或者我遇到了引用的限制,当与计算表达式一起使用时,我无法通过引用 基本上,我想使用一个计算F#工作流处理一个引用的lambda,定义如下。当尝试将这些工作流组合在一起时会出现问题。理想情况下,我希望使用let将工作流实例组合在一起!语法。我有点天真的尝试如下: type Workflow<'Env, 'Result> = Expr<'Env -> 'Result> type WorkflowSou
type Workflow<'Env, 'Result> = Expr<'Env -> 'Result>
type WorkflowSource<'Env, 'Result> = 'Env -> 'Result
type WorkflowBuilder() =
member x.Bind
(workflow: WorkflowSource<'Env, 'OldResult>,
selector: 'OldResult -> WorkflowSource<'Env, 'NewResult>) : WorkflowSource<'Env, 'NewResult> =
(fun env -> (selector (workflow env) env))
member x.Bind
(workflow: Workflow<'Env, 'OldResult>,
selector: 'OldResult -> WorkflowSource<'Env, 'NewResult>)
: Workflow<'Env, 'NewResult> =
<@ (fun env -> (selector ((%workflow) env) env)) @>
// This bind is where the trouble is
member x.Bind
(workflow: WorkflowSource<'Env, 'OldResult>,
selector: 'OldResult -> Workflow<'Env, 'NewResult>)
: Workflow<'Env, 'NewResult> =
<@ fun env ->
let newResultWorkflow = %(selector (workflow env))
newResultWorkflow env @>
member __.Return(x) = fun env -> x
member __.ReturnFrom(x : WorkflowSource<_, _>) = x
member __.Quote(x : Expr<WorkflowSource<_, _>>) : Workflow<_, _> = x
let workflow = new WorkflowBuilder()
只是想知道我正在努力实现的是可能的还是我做错了什么?在捕获最终引用表达式中的用户函数时,是否可以使上述简单情况正常工作
编辑:考虑到Tomas的答案,我也尝试了不使用WorkflowSource类型。仍有错误:System.InvalidOperationException:不允许使用“%”或“%”的第一类
在Microsoft.FSharp.Core.ExtraTopLevelOperators.剪接表达式[T](FSharpExpr`1表达式)中
键入WorkflowBuilder()=
成员x.绑定
(工作流:工作流,
选择器:“旧结果->工作流)
:工作流=
趣味环境->
成员返回(x)=乐趣环境->
成员_uu.ReturnFrom(x:Workflow)=x
成员(expr:expr)=expr
//此运行方法失败
成员_uu.Run(x:Expr):Workflow=fun(env:Expr这只是一个想法的草图,但我认为如果您将工作流表示为一个引用函数,而不是一个引用环境并返回一个引用结果的函数,则可以更进一步:
type Workflow<'Env, 'Result> = Expr<'Env> -> Expr<'Result>
事实证明,Quote
的定义是完全不相关的-编译器突出查找名为Quote
的成员的存在,但从不调用它(无论Quote
如何实现,它只引用计算表达式的主体)。这在我看来非常奇怪,但这就是计算表达式的工作方式。@kvb是的,在我看来就是这样。非常奇怪……我想你可以添加虚拟的引号,然后将实际代码放入运行中!是的,我相信这是标准的方法。谢谢大家的建议。编辑我的原始帖子以纳入acccount尝试。仍有错误,但至少有三个计算表达式进行了编译检查。作为更新,无论我如何努力,都会遇到此特定错误:System.InvalidOperationException:不允许使用第一类“%”或“%”。我认为这种想法也行不通。计算表达式的quote方法Pression builder为我提供了一个Expr>,我无法解决如何解包回工作流的问题,即在运行时不出现上述错误的Expr。在编译上述检查时考虑这个想法,至少在我目前对报价的了解下,可能不起作用。
type WorkflowBuilder() =
member x.Bind
(workflow: Workflow<'Env, 'OldResult>,
selector: 'OldResult -> Workflow<'Env, 'NewResult>)
: Workflow<'Env, 'NewResult> =
fun env -> <@ %(selector (%(workflow env)) env) @>
member __.Return(x) = fun Env -> <@ x @>
member __.ReturnFrom(x: Workflow<_, _>) = x
member __.Quote(expr: Expr<Workflow<'Env, 'Result>>) = expr
// This run method fails
member __.Run(x : Expr<Workflow<'Env, 'Result>>) : Workflow<'Env, 'Result> = fun (env: Expr<'Env>) -> <@ %((%x) env) @>
let workflow = new WorkflowBuilder()
// Env of type int for testing
let getRandomNumber (kernel: Expr<int>) = <@ (new Random()).Next() @>
let workflow1 = workflow {
let! randomNumber = getRandomNumber
let otherValue = 2
let! randomNumber2 = getRandomNumber
return randomNumber + otherValue + randomNumber2
}
// This fails due to quotation slicing issue
workflow1 <@ 0 @>
type Workflow<'Env, 'Result> = Expr<'Env> -> Expr<'Result>
member x.Bind
(workflow: WorkflowSource<'Env, 'OldResult>,
selector: 'OldResult -> WorkflowSource<'Env, 'NewResult>) : WorkflowSource<'Env, 'NewResult> =
(fun env -> (selector (workflow env) env))
member x.Bind
(workflow: Workflow<'Env, 'OldResult>,
selector: 'OldResult -> WorkflowSource<'Env, 'NewResult>)
: Workflow<'Env, 'NewResult> =
fun env -> <@ selector %(workflow env) %env @>
// This bind is where the trouble is
member x.Bind
(workflow: WorkflowSource<'Env, 'OldResult>,
selector: 'OldResult -> Workflow<'Env, 'NewResult>)
: Workflow<'Env, 'NewResult> =
fun env -> <@ %(selector (workflow %env) env) @>
member __.Quote(x : Expr<WorkflowSource<_, _>>) : Workflow<_, _> =
fun env -> <@ (%x) %env @>