10

由于作者已弃用钠,因此我正在尝试将我的代码移植到反应香蕉。但是,两者之间似乎存在一些我很难克服的不一致之处。

例如,在钠中很容易检索行为的当前值:

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

我看不到如何在反应香蕉中做到这一点

(我想要这个的原因是因为我试图将行为导出为 dbus 属性。可以从其他 dbus 客户端查询属性)

编辑:替换了“民意调查”这个词,因为它具有误导性

4

3 回答 3

1

如果您有一个 Behavior 对您的属性的值进行建模,并且您有一个 Event 对属性值的传入请求进行建模,那么您可以使用(<@) :: Behavior b -> Event a -> Event b1来获取在传入请求时发生的具有属性值的新事件当时有)。然后,您可以将其转换为您需要采取的实际 IO 操作来回复请求并reactimate照常使用。


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

于 2016-01-14T02:04:51.850 回答
0

出于概念/架构的原因,Reactive Banana 具有从Event到的功能Behavior,但反之则不然,考虑到 FRP 的性质和含义,它也很有意义。我很确定您可以编写一个轮询函数,但您应该考虑更改底层代码以公开事件。

你有什么理由不能把你的Behavior变成一个Event?如果没有,那将是解决您的问题的好方法。(从理论上讲,它甚至可能揭示您迄今为止一直忽略的设计缺陷。)

于 2016-01-12T23:17:12.403 回答
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 ()
于 2016-01-27T19:17:27.910 回答