由於鈉已被作者deprecated我試圖將我的代碼移植到反應香蕉。然而,兩者之間似乎有些不協調,我很難過度。從外部網絡採樣行爲
例如,鈉很容易檢索行爲的當前值:
retrieve :: Behaviour a -> IO a
retrieve b = sync $ sample b
我不明白如何在無功香蕉
(我想之所以這樣做這是因爲我想要的行爲導出爲DBUS財產屬性可以從其他DBUS客戶查詢)
編輯:代替「民意調查」,因爲它是誤導
由於鈉已被作者deprecated我試圖將我的代碼移植到反應香蕉。然而,兩者之間似乎有些不協調,我很難過度。從外部網絡採樣行爲
例如,鈉很容易檢索行爲的當前值:
retrieve :: Behaviour a -> IO a
retrieve b = sync $ sample b
我不明白如何在無功香蕉
(我想之所以這樣做這是因爲我想要的行爲導出爲DBUS財產屬性可以從其他DBUS客戶查詢)
編輯:代替「民意調查」,因爲它是誤導
答案似乎是 「這有點可能」。
但是,它可以與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()
由於概念/體系結構的原因,反應性香蕉的功能從Event
到Behavior
,但反之亦然,鑑於玻璃鋼的性質和含義,它也是有意義的。我確信你可以寫一個輪詢函數,但是你應該考慮修改底層代碼來公開事件。
是否有理由不能將Behavior
更改爲Event
?否則,這將是解決您的問題的好方法。 (它在理論上甚至可以揭示到目前爲止您已忽略的一個設計缺陷。)
如果您有一個行爲建模屬性的值,並且您有一個事件建模屬性值的傳入請求,那麼您可以使用(<@) :: Behavior b -> Event a -> Event b
在傳入請求時使用該屬性具有的值來獲取新事件)。然後,您可以將其轉換爲您需要採取的實際IO操作來回復請求並像往常一樣使用reactimate
。
沒有任何操作可以回覆該請求,而是爲回覆發送了dbus屬性回調集的返回值。我可以做的是創建一個新的IORef,並將請求傳遞到事件中,使用reactimate將採樣值放入IORef中,然後在事件調用返回時再讀取請求處理函數中的IORef。然而,這需要兩個地方的交互代碼(事件網絡和回調函數),這使得代碼難以維護,與鈉提供的簡單解決方案相比。 – Philonous
在概念層面,採樣'Behavior'纔有意義,在'Moment'的情況下,即在特定的時刻,這是'IO'不提供的。這不僅僅是一個理論問題,而且對於實現的內部一致性很重要,所以我很猶豫要添加一個這樣的函數。你能詳細說明你想使用這個(dbus)的具體環境嗎?有機會可以用不同的方式表達。 –
當創建接收到請求時調用的屬性時,設置回調函數(getCurrentState :: IO Response)。所述回調函數應該以某種方式檢索行爲的當前值(可能通過調用由newAddHandler創建的處理函數來觸發事件來使用「current」或「now」的相同概念)。 – Philonous
事實證明,我可以用reactive-banana提供的工具重新實現相同的行爲:[gist](https://gist.github.com/b334c81018628fd6cfc8)。在這個例子中,我使用unsafePerformIO儘可能地接近鈉的語義,但這絕不是必須的(我只需要通過IO操作即可)。所以問題就變成了:是否有理由不通過重複的「執行」而不是直接使用編譯來構建網絡? – Philonous