2015-09-15 9 views
6

私はこれを調べて答えを得ようと苦労しました。私は明らかな答えがあると確信していますが、私はそれを見つけることができません。または私は、計算式で使用するときに渡すことができない引用の制限を打ちました。計算式を使用して引用符付き関数を作成する

基本的には、計算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 @> 
に許可しないれます

答えて

2

これはアイデアだけのラフスケッチですが、私はあなたがいない引用された機能としてではなく、引用された環境を取り、引用された結果を返す関数としてワークフローを表す場合は、さらに得ることができると思う:

type Workflow<'Env, 'Result> = Expr<'Env> -> Expr<'Result> 

次に、すべてのバインドを確実に実装できます。

それはコンパイラが Quoteでコードを無視しているようですので、私たちは WorkflowWorkflowSourceをオン引用符を追加しても Expr<WorkflowSource<_>>値があるので、あなたはまだエラーを取得する - と述べ
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) @> 

、私はこれは非常にあなたが必要とするすべてではないと思います私はバインドの別のオーバーロードがそれを解決するかもしれないと思う。

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

それはQuote' 'の定義は完全に無関係であることが判明 - コンパイラがQuote''という名前のメンバーの存在のためにルックスを張り出しが、今までそれを起動していない(それだけに関わらずの計算式のボディを引用'Quote'がどのように実装されているか)。これは非常に変わったIMOですが、それは計算式がどのように機能するかです。 – kvb

+0

@kvbええ、それは私に見えた方法です。かなり奇妙な...私はダミーの 'Quote'を追加し、実際のコードを' Run'に入れてもいいと思います! –

+0

はい、これは標準的なアプローチだと思います。 – kvb

関連する問題