如何回顾前一刻

时间:2015-07-27 05:01:02

标签: haskell frp reactive-banana

我每时每刻都在阅读按钮的状态(无论是否被按下):

readButton :: IO Boolean
readButton = ...

main = do
    (add, fire) <- newAddHandler
    network <- compile (desc add)
    actuate network
    forever $ do
        buttonState <- readButton
        fire buttonState

desc addButtonEvent = do
    eButtonState <- fromAddHandler addButtonEvent
    ...

所有读取状态都存储在网络说明eButtonState中的desc

当当前时刻的状态为1且前一时刻为0时,该按钮被视为新按下。因此,如果事件序列是一个列表,则函数将按如下方式编写:

f :: [Bool] -> Bool
f (True:False:_) = True
f _              = False

我想将此功能应用于eButtonState,以便我知道此按钮是否是新按下的按钮。

有可能吗?你会怎么做?如果有更好或更常见的想法或方法来实现这一目标,我将不胜感激。

1 个答案:

答案 0 :(得分:3)

这是一种方式(这是一个可运行的演示):

import Reactive.Banana
import Reactive.Banana.Frameworks
import Control.Monad
import Control.Applicative -- Needed if you aren't on GHC 7.10.

desc addDriver = do
    -- Refreshes the button state. Presumably fired by external IO.
    eButtonDriver <- fromAddHandler addDriver
    let -- Canonical repersentation of the button state.
        bButtonState = stepper False eButtonDriver
        -- Observes the button just before changing its state.
        ePreviousState = bButtonState <@ eButtonDriver
        -- Performs the test your f function would do.
        newlyPressed :: Bool -> Bool -> Bool
        newlyPressed previous current = not previous && current
        -- Applies the test. This works because eButtonDriver and
        -- ePreviousState are fired simultaneously.
        eNewlyPressed = unionWith newlyPressed
            ePreviousState eButtonDriver
        -- The same but more compactly, without needing ePreviousState.
        {-
        eNewlyPressed = newlyPressed <$> bButtonState <@> eButtonDriver
        -}
    reactimate (print <$> eNewlyPressed)

main = do
    (addDriver, fireDriver) <- newAddHandler
    network <- compile (desc addDriver)
    actuate network
    -- Demo: enter y to turn the button on, and any other string to
    -- turn it off.
    forever $ do
        buttonState <- (== "y") <$> getLine
        fireDriver buttonState

注意:

  • 事件是暂时的,行为是永久性的是决定您是需要行为还是事件流的一般规则。在这种情况下,您需要查看更新前按钮状态是什么,以确定它是否是新更新的。然后,自然要做的是用行为(bButtonState)来表示按钮状态,该行为由外部触发的事件(eButtonDriver)更新。
  • 有关组合器正在做什么的详细信息,请参阅Reactive.Banana.Combinators
  • 有关反应性香蕉中事件和行为更新时间的细则,请参阅this question
  • 根据您要执行的操作,changes功能可能很有用。请注意文档中提到的与之相关的警告。