2013-10-15 31 views
1

所以,我想建立一個自定義計算表達式,讓我把這個 -如何將前向管道表達式轉換爲計算表達式?

testWorld |> 
    subscribe ClickTestButtonAddress [] addBoxes |> 
    addScreen testScreen TestScreenAddress |> 
    setP (Some TestScreenAddress) World.optActiveScreenAddress |> 
    addGroup testGroup TestGroupAddress |> 
    addEntityGuiLabel (testLabelGuiEntity, testLabelGui, testLabel) TestLabelAddress |> 
    addEntityGuiButton (testButtonGuiEntity, testButtonGui, testButton) TestButtonAddress |> 
    addEntityActorBlock (testFloorActorEntity, testFloorActor, testFloor) TestFloorAddress |> 
    (let hintRenderingPackageUse = HintRenderingPackageUse { FileName = "AssetGraph.xml"; PackageName = "Misc"; HRPU =() } 
    fun world -> { world with RenderMessages = hintRenderingPackageUse :: world.RenderMessages }) |> 
    (let hintAudioPackageUse = HintAudioPackageUse { FileName = "AssetGraph.xml"; PackageName = "Misc"; HAPU =() } 
    fun world -> { world with AudioMessages = hintAudioPackageUse :: world.AudioMessages }) 

弄成這個樣子 -

fwd { 
    do! subscribe ClickTestButtonAddress [] addBoxes 
    do! addScreen testScreen TestScreenAddress 
    do! setP (Some TestScreenAddress) World.optActiveScreenAddress 
    do! addGroup testGroup TestGroupAddress 
    do! addEntityGuiLabel (testLabelGuiEntity, testLabelGui, testLabel) TestLabelAddress 
    do! addEntityGuiButton (testButtonGuiEntity, testButtonGui, testButton) TestButtonAddress 
    do! addEntityActorBlock (testFloorActorEntity, testFloorActor, testFloor) TestFloorAddress 
    let hintRenderingPackageUse = HintRenderingPackageUse { FileName = "AssetGraph.xml"; PackageName = "Misc"; HRPU =() } 
    do! fun world -> { world with RenderMessages = hintRenderingPackageUse :: world.RenderMessages } 
    let hintAudioPackageUse = HintAudioPackageUse { FileName = "AssetGraph.xml"; PackageName = "Misc"; HAPU =() } 
    do! fun world -> { world with AudioMessages = hintAudioPackageUse :: world.AudioMessages }} 
    <| runFwd testWorld 

這是可能的,或接近的東西可能嗎?如果是這樣,可以採取什麼方法?這是一個monad,還是更小的東西?

+1

只是想知道,使用計算表達式有什麼好處? (流水線符號對我來說看起來很好......) –

+0

最簡單的方法就是在每個單獨的操作上設置斷點。這條管道實際上是不可爆炸的,AFAICT。真相被告知,我的偏好是讓VS能夠在管道內放置斷點,但我沒有看到發生這種情況。除此之外,我想要添加一些自定義的CE運營商。我最終試圖在World類型的層次上構建一個'腳本'計算表達式事物。 –

+0

當然,我的評論假設有一些方法可以讓當前世界脫離調試器... Tho也許不會有:(......也許我應該回到正常的基於let的代碼? –

回答

6

也許我應該回去做這一點 -

let tw_ = testWorld 
let tw_ = subscribe ClickTestButtonAddress [] addBoxes tw_ 
let tw_ = addScreen testScreen TestScreenAddress tw_ 
let tw_ = setP (Some TestScreenAddress) World.optActiveScreenAddress tw_ 
let tw_ = addGroup testGroup TestGroupAddress tw_ 
let tw_ = addEntityGuiLabel (testLabelGuiEntity, testLabelGui, testLabel) TestLabelAddress tw_ 
let tw_ = addEntityGuiButton (testButtonGuiEntity, testButtonGui, testButton) TestButtonAddress tw_ 
let tw_ = addEntityActorBlock (testFloorActorEntity, testFloorActor, testFloor) TestFloorAddress tw_ 
let tw_ = { tw_ with RenderMessages = hintRenderingPackageUse :: tw_.RenderMessages } 
{ tw_ with AudioMessages = hintAudioPackageUse :: tw_.AudioMessages } 

它調試罰款(你可以找到tw_的所有先前版本的自動窗口,可以在每一個操作步驟調試),這是不是太詳細我想。

+0

我怎麼看不到這個。我的意思是,monad在這裏我不會更好地爲你服務 – nicolas

1

你需要一個let!傳播monadic狀態。

所以我想你已經有了monad:它是普通的舊的let,它接受當前的綁定,添加一個新的綁定,並在隨後的計算中傳遞它!

2

如果使用ExtCore庫(上的NuGet可用),它提供了一個名爲tap操作它是專門提供幫助調試流水線表達式。你可以通過「點擊」你的管道來使用它,這個管道應用了一個動作函數(返回unit)到管道中某個點的值,然後這個值被傳遞,所以它可以像預期的一樣流過管道。

例如:

testWorld 
|> subscribe ClickTestButtonAddress [] addBoxes 
|> addScreen testScreen TestScreenAddress 
// Check to see if the screen was added correctly 
|> tap (fun world -> 
    // TODO : Insert code to check if the screen was added. 
    // Or, put some dummy code here so you can set a breakpoint 
    // on it to inspect 'world' in the debugger. 
    ()) 
|> setP (Some TestScreenAddress) World.optActiveScreenAddress 
|> addGroup testGroup TestGroupAddress 
|> addEntityGuiLabel (testLabelGuiEntity, testLabelGui, testLabel) TestLabelAddress 
|> addEntityGuiButton (testButtonGuiEntity, testButtonGui, testButton) TestButtonAddress 
|> addEntityActorBlock (testFloorActorEntity, testFloorActor, testFloor) TestFloorAddress 
|> (let hintRenderingPackageUse = HintRenderingPackageUse { FileName = "AssetGraph.xml"; PackageName = "Misc"; HRPU =() } 
    fun world -> { world with RenderMessages = hintRenderingPackageUse :: world.RenderMessages }) 
|> (let hintAudioPackageUse = HintAudioPackageUse { FileName = "AssetGraph.xml"; PackageName = "Misc"; HAPU =() } 
    fun world -> { world with AudioMessages = hintAudioPackageUse :: world.AudioMessages }) 

一個相關函數,tapAssert,可以用來調試斷言插入您的管道。

+0

我很欣賞這個建議,但我真的需要能夠在不重新啓動程序的情況下插入斷點。 –

2

State或Writer Monad可能很有用,但如果您想使用調試器忘記Monads,則更糟。 有一件事你可以做的是重新定義管道運營商是這樣的:

let (|>) a b = printfn "Value is: %A" a; b a 

5 
    |> ((+) 40) 
    |> string 
    |> Seq.singleton 
    |> Seq.toArray 

你會看到:

Value is: 5 
Value is: 45 
Value is: "45" 
Value is: seq ["45"] 
val it : string [] = [|"45"|] 

或者你也可以代替印刷,積聚在對象的可變列表的結果。

let mutable results = [] : obj list 
let (|>) a b = 
    results <- results @ [box a] // or set a breakpoint here 
    b a 
... 
val mutable results : obj list = [5; 45; "45"; <seq>] 

這幾乎就像作者monad。

但是,如果你一定要使用調試器(這不是我最喜歡的工具),你是let的解決方案是好的,但你必須改變你的代碼,並且將管道鬆開,在這種情況下,它可能會更好在(|>)函數的主體中添加一個斷點。

+0

嘿,這很酷,但我絕對不想打印世界:)在保護monads方面,至少你可以在每個操作上放一個斷點 - 只是不要嘗試去調試:) –

+0

你也可以在該操作符的重新定義的主體中設置一個斷點。只需多行,我在最後一個樣本中添加了一條評論。 – Gustavo

相關問題