Я огляделся и изо всех сил пытался получить ответ на этот вопрос; Я уверен, что есть очевидный ответ, но я просто не могу его найти; или я столкнулся с ограничением цитат, которое я не могу передать при использовании с вычислительными выражениями.
В основном я хочу работать с цитируемой лямбдой, определенной, как показано ниже, с использованием вычислительного рабочего процесса F #. Проблема возникает при попытке объединить эти рабочие процессы вместе. В идеале я хочу скомпоновать экземпляры Workflow ‹'Env,' Result> вместе, используя let! синтаксис. Моя несколько наивная попытка ниже:
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()
Третий член привязки дает мне ошибку компилятора: «Переменная env» привязана в кавычки, но используется в нарезанном выражении », что в некотором роде имеет смысл. Вопрос в том, как мне это обойти. Я определил вышеизложенное как попытку заставить работать простые нижеприведенные случаи.
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)
}
Просто интересно, возможно ли то, чего я пытаюсь достичь, или я что-то делаю не так? Можно ли заставить вышеуказанные простые случаи работать при захвате пользовательских функций внутри заключительного цитируемого выражения?
РЕДАКТИРОВАТЬ: Я также пробовал без типа WorkflowSource с учетом ответа Томаса. Не повезло с ошибкой: System.InvalidOperationException: использование первого класса '%' или '%%' не разрешено в Microsoft.FSharp.Core.ExtraTopLevelOperators.SpliceExpression [T] (выражение FSharpExpr`1)
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 @>