私はこれを調べて答えを得ようと苦労しました。私は明らかな答えがあると確信していますが、私はそれを見つけることができません。または私は、計算式で使用するときに渡すことができない引用の制限を打ちました。計算式を使用して引用符付き関数を作成する
基本的には、計算F#ワークフローを使用して以下のように定義された引用ラムダを使用したいと考えています。この問題は、これらのワークフローを一緒に構成しようとするときに発生します。理想的には、ワークフロー<の 'Env、' Result>インスタンスをlet!構文。私のやや素朴な試みは以下の通りです:「変数 『ENVは』引用に結合したがスライスされた式で使用される」ちょっと意味があります:
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()
第三バインドメンバーは私にコンパイラエラーが発生します。問題はどのように私はそれを回避することです。私は上記のことを、以下の単純なケースを動作させようとする試みとして定義しました。
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 @>
に許可しないれます
それはQuote' 'の定義は完全に無関係であることが判明 - コンパイラがQuote''という名前のメンバーの存在のためにルックスを張り出しが、今までそれを起動していない(それだけに関わらずの計算式のボディを引用'Quote'がどのように実装されているか)。これは非常に変わったIMOですが、それは計算式がどのように機能するかです。 – kvb
@kvbええ、それは私に見えた方法です。かなり奇妙な...私はダミーの 'Quote'を追加し、実際のコードを' Run'に入れてもいいと思います! –
はい、これは標準的なアプローチだと思います。 – kvb