How to look back at a previous moment

I read the state of the button (whether pressed or not) every moment:

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
    ...

All read states are stored in the eButtonStatenetwork description desc.

The button is considered to be pressed again when the current state of the moment 1, with the previous moment 0. So, if the sequence of events was a list, the function would be written like this:

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

I want to apply this function to eButtonStateto find out if a button is currently pressed or not.

Is it possible? How would you do that? I would appreciate if there is a better or more general idea or method to achieve this.

+4
source share
1 answer

Here is one way (this is a demo version):

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

Notes:

+3

Source: https://habr.com/ru/post/1599797/


All Articles