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

时间:2015-09-15 12:06:50

标签: f# quotations computation-expression

我环顾四周,努力想要得到答案;我确定有一个明显的答案,但我似乎无法找到它;或者我已经达到了与计算表达式一起使用时无法通过的引用限制。

基本上我想使用计算F#工作流程来处理如下定义的lambda。尝试将这些工作流程组合在一起时会出现问题。理想情况下,我想要撰写工作流程<' Env,'结果>实例一起使用let!句法。我有点天真的尝试如下:

<?php
$contents = file('file.scss'); //array with lines from file
$linenum = 0;
foreach($contents as $key=>$line)
{
  // a line can start with 0 or more spaces, then // (maybe, maybe not), then 0 or more space, then something entirely unknown, then a : then something entirely unknown and then a ;
  //[0] = the whole line [1] = the // or not [2] is the variablename [3] = the variabel value
  if (preg_match('/[ ]*([\/]{2})?[ ]*(.*?):(.*?);/is', $line, $matches))
  {
    $variablename = $matches[2];
    $variablevalue = $matches[3];
    if ($variablename == '$myvar')
    {   
      if ($matches[1] != '//') //if it is not commented out
        $contents[$key] = '$mainColor: red;'; //replace the whole line, if you want to replace only the color you can maybe use str_replace to replace the $variablevalue to something else?
        //$contents[$key] = str_replace($variablevalue, 'red', $line); // this line is untested
      break;
    }   
  }
}

//do something with the result:
echo implode($contents);

第三个绑定成员给出了编译器错误:&#34;变量&#34; env&#34;在引用中绑定但在切片表达式中使用&#34;哪种有道理。问题是我该如何解决它。我已经将上述内容定义为试图让下面的简单案例起作用。

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()

只是想知道我想要实现的是可能还是我做错了什么?在最终引用的表达式中捕获用户函数时,是否可以使上述简单案例工作?

编辑:我也尝试过没有WorkflowSource类型考虑到Tomas&#39;回答。没有运气仍然有错误:System.InvalidOperationException:头等使用&#39;%&#39;或&#39; %%&#39;是不允许的    在Microsoft.FSharp.Core.ExtraTopLevelOperators.SpliceExpression [T](FSharpExpr`1表达式)

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)
}

1 个答案:

答案 0 :(得分:2)

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

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) @>

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

member __.Quote(x : Expr<WorkflowSource<_, _>>) : Workflow<_, _> = 
  fun env -> <@ (%x) %env @>