Rozejrzałem się i starałem się uzyskać odpowiedź na to; Jestem pewien, że istnieje oczywista odpowiedź, ale po prostu nie mogę tego znaleźć; lub trafiłem na ograniczenie cytatów, których nie mogę przekazać, gdy są używane z wyrażeniami obliczeniowymi.Tworzenie cytowanych funkcji za pomocą wyrażeń obliczeniowych
Zasadniczo chcę pracować z cytowaną wartością lambda zdefiniowaną poniżej, wykorzystując przepływ pracy F #. Problem pojawia się, próbując skomponować te przepływy pracy. Idealnie chciałbym skomponować wystąpienia Workflow < "Env," Result> razem za pomocą let! składnia. My nieco naiwna próba jest poniżej:
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()
Trzeci członek wiążą daje mi błąd kompilatora: „Zmienna«env»jest związany w cytacie, ale używane w plastrach wypowiedzi”, które trochę sens. Pytanie brzmi, jak sobie z tym poradzić. Zdefiniowałem powyższe jako próbę, aby spróbować wykonać poniższe proste czynności.
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)
}
Zastanawiam się, czy to, co próbuję osiągnąć, jest możliwe, czy też robię coś nie tak? Czy jest możliwe, aby powyższe proste przypadki działały podczas przechwytywania funkcji użytkownika w końcowym cytowanym wyrażeniu?
EDYCJA: Próbowałem również bez typu WorkflowSource, biorąc pod uwagę odpowiedź Tomas. Brak powodzenia nadal z powodu błędu: System.InvalidOperationException: Pierwsza klasa zastosowania '%' lub '%%' nie są dozwolone na Microsoft.FSharp.Core.ExtraTopLevelOperators.SpliceExpression [T] (wyrażenie 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 @>
Okazuje się, że definicja 'Quote' jest zupełnie nieistotny - kompilator wcina spojrzenia na obecność członka nazwie' Quote' ale nigdy go nie powoływać (to po prostu cytuje ciało wyrażenie obliczeń, niezależnie od jak implementuje się 'Quote'). To jest bardzo dziwna IMO, ale tak działają wyliczenia obliczeniowe. – kvb
@kvb Tak, tak to wyglądało dla mnie. Dość dziwne ... Przypuszczam, że można dodać manekina 'Quote' i umieścić rzeczywisty kod w' Run' chociaż! –
Tak, uważam, że to standardowe podejście. – kvb