2016-01-12 30 views
10

由於鈉已被作者deprecated我試圖將我的代碼移植到反應香蕉。然而,兩者之間似乎有些不協調,我很難過度。從外部網絡採樣行爲

例如,鈉很容易檢索行爲的當前值:

retrieve :: Behaviour a -> IO a 
retrieve b = sync $ sample b 

我不明白如何在無功香蕉

(我想之所以這樣做這是因爲我想要的行爲導出爲DBUS財產屬性可以從其他DBUS客戶查詢)

編輯:代替「民意調查」,因爲它是誤導

+0

在概念層面,採樣'Behavior'纔有意義,在'Moment'的情況下,即在特定的時刻,這是'IO'不提供的。這不僅僅是一個理論問題,而且對於實現的內部一致性很重要,所以我很猶豫要添加一個這樣的函數。你能詳細說明你想使用這個(dbus)的具體環境嗎?有機會可以用不同的方式表達。 –

+0

當創建接收到請求時調用的屬性時,設置回調函數(getCurrentState :: IO Response)。所述回調函數應該以某種方式檢索行爲的當前值(可能通過調用由newAddHandler創建的處理函數來觸發事件來使用「current」或「now」的相同概念)。 – Philonous

+1

事實證明,我可以用reactive-banana提供的工具重新實現相同的行爲:[gist](https://gist.github.com/b334c81018628fd6cfc8)。在這個例子中,我使用unsafePerformIO儘可能地接近鈉的語義,但這絕不是必須的(我只需要通過IO操作即可)。所以問題就變成了:是否有理由不通過重複的「執行」而不是直接使用編譯來構建網絡? – Philonous

回答

0

答案似乎是 「這有點可能」。

sample對應於valueB,但沒有直接等價於sync

但是,它可以與execute的幫助下重新實現:

module Sync where 

import Control.Monad.Trans 
import Data.IORef 
import Reactive.Banana 
import Reactive.Banana.Frameworks 

data Network = Network { eventNetwork :: EventNetwork 
         , run :: MomentIO() -> IO() 
         } 

newNet :: IO Network 
newNet = do 
    -- Create a new Event to handle MomentIO actions to be executed 
    (ah, call) <- newAddHandler 
    network <- compile $ do 
     globalExecuteEV <- fromAddHandler ah 
     -- Set it up so it executes MomentIO actions passed to it 
     _ <- execute globalExecuteEV 
     return() 
    actuate network 
    return $ Network { eventNetwork = network 
        , run = call -- IO Action to fire the event 
        } 

-- To run a MomentIO action within the context of the network, pass it to the 
-- event. 
sync :: Network -> MomentIO a -> IO a 
sync Network{run = call} f = do 
    -- To retrieve the result of the action we set up an IORef 
    ref <- newIORef (error "Network hasn't written result to ref") 
    -- (`call' passes the do-block to the event) 
    call $ do 
     res <- f 
     -- Put the result into the IORef 
     liftIO $ writeIORef ref res 
    -- and read it back once the event has finished firing 
    readIORef ref 

-- Example 
main :: IO() 
main = do 
    net <- newNet -- Create an empty network 
    (bhv1, set1) <- sync net $ newBehavior (0 :: Integer) 
    (bhv2, set2) <- sync net $ newBehavior (0 :: Integer) 
    set1 3 
    set2 7 
    let sumB = (liftA2 (+) bhv1 bhv2) 
    print =<< sync net (valueB sumB) 
    set1 5 
    print =<< sync net (valueB sumB) 
    return() 
0

由於概念/體系結構的原因,反應性香蕉的功能從EventBehavior,但反之亦然,鑑於玻璃鋼的性質和含義,它也是有意義的。我確信你可以寫一個輪詢函數,但是你應該考慮修改底層代碼來公開事件。

是否有理由不能將Behavior更改爲Event?否則,這將是解決您的問題的好方法。 (它在理論上甚至可以揭示到目前爲止您已忽略的一個設計缺陷。)

+0

我不知道這是如何適用於我的問題。我相當肯定它應該是一個行爲,因爲它模擬了一個隨時間變化的值。我的問題是我有一個來自網絡的請求,我想用這個行爲的當前值來回答。當然,我可以將這個請求的到達作爲一個事件(通過觸發一個處理程序)來建模,但是這隻會將請求送入(frp-)網絡,它不能檢索返回的結果。 – Philonous

+0

我對「民意調查」一詞的選擇可能是誤導性的。我不想檢查數值何時發生變化,而是希望在特定時間檢索行爲的價值,例如,回答網絡請求(想想HTTP) – Philonous

+0

哦,我明白了,我的壞話呢:) –

1

如果您有一個行爲建模屬性的值,並且您有一個事件建模屬性值的傳入請求,那麼您可以使用(<@) :: Behavior b -> Event a -> Event b 在傳入請求時使用該屬性具有的值來獲取新事件)。然後,您可以將其轉換爲您需要採取的實際IO操作來回復請求並像往常一樣使用reactimate


https://hackage.haskell.org/package/reactive-banana-1.1.0.0/docs/Reactive-Banana-Combinators.html#v:-60--64-

+0

沒有任何操作可以回覆該請求,而是爲回覆發送了dbus屬性回調集的返回值。我可以做的是創建一個新的IORef,並將請求傳遞到事件中,使用reactimate將採樣值放入IORef中,然後在事件調用返回時再讀取請求處理函數中的IORef。然而,這需要兩個地方的交互代碼(事件網絡和回調函數),這使得代碼難以維護,與鈉提供的簡單解決方案相比。 – Philonous