首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用计算表达式组成引用的函数

使用计算表达式组成引用的函数
EN

Stack Overflow用户
提问于 2015-09-15 20:06:50
回答 1查看 417关注 0票数 6

我环顾四周,努力寻找这个问题的答案;我确信有一个显而易见的答案,但我就是找不到它;或者我遇到了在使用计算表达式时无法通过的引号限制。

基本上,我希望使用计算F#工作流处理如下定义的引用的lambda。当试图将这些工作流组合在一起时,问题就出现了。理想情况下,我希望使用let!语法将工作流<‘Env 'Result>实例组合在一起。

代码语言:javascript
复制
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()

第三个bind成员告诉我编译器错误:“变量"env”绑定在引号中,但用在一个切片表达式中“,这有点道理。问题是我如何绕过它。我将上面的定义定义为尝试让下面的简单情况正常工作。

代码语言:javascript
复制
let getNumber (env: EnvironmentContext) = (new Random()).Next()

let workflow1 = workflow {
    let! randomNumber = getNumber
    let customValue = randomNumber * 10
    return (globalId * customValue)
}

// From expression to non expression bind case
let workflow2a = workflow {
    let! workflow1 = workflow1
    let! randomNumber = getNumber
    return (randomNumber + workflow1)
}

// From non-expression to expression bind case
let workflow2 = workflow {
    let! randomNumber = getNumber
    let! workflow1 = workflow1
    return (randomNumber + workflow1)
}

只是想知道我想要实现的是不是可能,还是我做错了什么?是否有可能在捕获最终引用表达式中的用户函数的同时,让上述简单的情况正常工作?

编辑:考虑到Tomas的回答,我也尝试了不使用WorkflowSource类型。错误: System.InvalidOperationException:在Microsoft.FSharp.Core.ExtraTopLevelOperators.SpliceExpressionT中不允许使用'%‘或'%%’的第一类

代码语言:javascript
复制
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 @>
EN

回答 1

Stack Overflow用户

发布于 2015-09-15 20:49:24

这只是一个想法的粗略草图,但我认为如果您不将工作流表示为引用的函数,而是将其表示为采用引用的环境并返回引用的结果的函数,则可以更进一步:

代码语言:javascript
复制
type Workflow<'Env, 'Result> = Expr<'Env> -> Expr<'Result>

然后,您肯定可以实现所有的绑定:

代码语言:javascript
复制
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) @>

也就是说,我认为这还不是你需要的全部-编译器似乎忽略了Quote中的代码,所以即使我们添加了将WorkflowSource转换为Workflow的引号,你仍然会得到错误,因为有Expr<WorkflowSource<_>>值-但我认为另一个绑定重载可能会解决这个问题。

代码语言:javascript
复制
member __.Quote(x : Expr<WorkflowSource<_, _>>) : Workflow<_, _> = 
  fun env -> <@ (%x) %env @>
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32585674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档