reactive-banana-wx`sink`不会生成启用后置处理的事件

时间:2012-11-27 08:30:41

标签: haskell reactive-programming frp reactive-banana

我目前正在使用reactive-banana和reactive-banana-wx软件包重新设计一个传统的wxHaskell。但是,为了避免动态网络构建(我遇到了MVar上的线程块),我现在通过预构建一组固定的wxHaskell小部件来模仿这一点,我根据需要设置了可见性。可见性由sink函数设置为Behavior。但是,wxHaskell要求在通过sink对所有这些小部件进行适当修改之后,需要随后更改包含这些小部件的面板的布局。这意味着sink实际上应该是网络的一部分,因此它是一个可以触发并等待布局更改的事件。就目前而言,sink将您带出事件网络,在sink操作完成后无法触发事件。我确实试图让sink适应这样的事情:

sink' :: Frameworks t =>
    w -> [Prop' t w] -> Moment t (Event t ())
sink' widget props = do
    es <- mapM sink1 props
    return $ unions es
  where
    sink1 (attr :== b) = do
        x <- initial b
        liftIOLater $ set widget [attr := x]
        e <- changes b
        return $ (\x -> unsafePerformIO $ set widget [attr := x]) <$> e

然而,unsafePerformIO没有被执行。如何实现所需的行为,即允许通过Event等待(wxHaskell)IO?

1 个答案:

答案 0 :(得分:2)

基本上,您希望确保reactimate中的IO操作按特定顺序执行?也就是说,您希望确保在小部件属性设置之后设置布局。

有几种方法可以指定顺序:

  1. 使用unionunionWith和/或collect来确定同步事件的顺序。
  2. 使用reactimate按照Moment monad中出现的顺序执行的事实。 (尽管严格来说,当您使用动态事件切换的observeE组合子时,情况不再如此。)
  3. 在您的特定情况下,可以按如下方式应用这些想法。

    对于1,您可以创建包含IO操作的事件,并将其与稍后的布局相结合

    sink' :: Frameworks t =>
        w -> [Prop' t w] -> Moment t (Event t (IO ()))
    sink' widget props = do
        es <- mapM sink1 props
        return $ foldr1 (unionWith (>>)) es
      where
        sink1 (attr :== b) = do
            x <- initial b
            liftIOLater $ set widget [attr := x]
            e <- changes b
            return $ (\x -> set widget [attr := x]) <$> e
    

    对于2,您可以简单地使用普通的sink函数,并确保最后设置布局。

    do
        sink widget1 [ visible :== bBool ]
        sink window1 [ layout  :== bLayout ]
    

    monad中sink函数的排序可确保最后设置布局。


    另请注意,由于reactive-banana 0.7,您可以使用动态事件切换来为一组可变小部件建模。有关演示,请参阅BarTab.hs example。此示例还设置布局。

    您表示在使用动态网络时遇到了MVar块。这可能是因为您以触发网络中另一个事件的方式创建窗口小部件。不幸的是,这在语义上是不合理的 - 它对应于取决于他们自己的未来版本的值 - 并且程序通过深入到底层来响应。