2015-09-15 14 views
6

Buna baktım ve bunun cevabını almak için uğraştım; Eminim bariz bir cevap var ama onu bulamıyorum. veya hesaplama ifadeleriyle kullanıldığında kullanamayacağım bir alıntılama sınırına çarptım.Hesaplama ifadeleri kullanılarak alıntılanmış işlevleri oluşturma

Temel olarak, bir hesaplama F # iş akışı kullanarak aşağıda belirtilen bir alıntı lambda ile çalışmak istiyorum. Bu iş akışlarını birlikte oluşturmaya çalışırken sorun geliyor. İdeal olarak, iş akışını kullanarak Workflow < 'Env,' Sonuç> örneklerini oluşturmak istiyorum! sözdizimi. Benim biraz da naif girişimi aşağıdadır: "değişken 'env' tırnak içinde bağlı ama dilimlenmiş ifadesinde kullanılan" tür mantıklı:

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

üçüncü bağlama üyesi bana derleyici hata veriyor. Soru şu ki, etrafımdan nasıl geçebilirim. Yukarıdakileri, basit durumların çalışmasını sağlamaya çalışmak için bir girişim olarak tanımladım.

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

Sadece ne elde etmek çalışıyorum mümkün olup olmadığını merak veya yanlış bir şey yapıyorum? Son işlem yapılan ifadenin içinde kullanıcı işlevlerini yakalarken yukarıdaki basit vakaları çalışmak mümkün mü?

DÜZENLEME: Ayrıca Tomas'ın yanıtını dikkate alarak WorkflowSource türü olmadan da denedim. System.InvalidOperationException: error ile de başarılı '%' veya %% birinci sınıfı, kullanımları Microsoft.FSharp.Core.ExtraTopLevelOperators.SpliceExpression [T] (FSharpExpr`1 sentezleme)

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 @> 
de izin verilmez

cevap

2

Bu bir fikrin sadece kaba bir taslaktır, ama iş akışını temsil eğer daha da gelemeyeceğim bir alıntı işlevi olarak, ancak bir alıntı sonucu bir alıntı ortamı alır ve döndüren bir fonksiyon olarak:

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

O zaman, tüm bağlamaları kesinlikle uygulayabilirsiniz:

o derleyici Quote kod görmezden gibi görünüyor, bu yüzden Workflow içine WorkflowSource döner alıntı eklemek bile Expr<WorkflowSource<_>> değerler olduğundan, hala hataları olsun - dedi
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) @> 

, bu oldukça tek ihtiyacınız olmadığını düşünüyorum - ama bindiğimin başka bir aşırı yüklenmesinin bunu çözebileceğini düşünüyorum.

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

O Quote' 'tanımı tamamen alakasız olduğu ortaya çıktı - derleyici Quote'' adlı bir üyesinin varlığı için görünüyor Arabistan'dan ama Hiç çağırmak değil (sadece bakılmaksızın hesaplama ifadenin vücudunu tırnak Alıntı nasıl uygulanır? Bu son derece garip IMO'dur, ancak hesaplama ifadeleri bu şekilde çalışır. – kvb

+0

@kvb Evet, bana öyle görünüyor. Oldukça garip ... Ben "Alıntı" kukla ekleyebilir ve 'Run' olsa gerçek kodu koyabilirsiniz varsayalım! –

+0

Evet, bunun standart yaklaşım olduğuna inanıyorum. – kvb