haskellfrpreactive-banana

How to know what made a behavior change?


I'm writing a network description for a a listbox logic.
It's really simple: I have a behavior for the (Maybe) current selected item, and I want it so that whenever the user adds a new item to the list, the current selected item will select the just-created value.

It's also possible for the user to remove items from the list, and cause various of other changes, so I have to know when a new item is created; I can't just select the last item on every change.

I don't really have any code to show for it because all my speculations on what to do can't even be written with the API*, but I have the context of Frameworks t and (simplified):

bDb :: Behavior t [Entry] -- Created with accumB.
bSelected :: Behavior t (Maybe Entry) -- Created with accumB.
eAddEntry :: Event t () -- User clicked an add button. Created with fromAddHandler.

* Well, I did think about using eAddEntry to select the last entry, but that's so bad and even if it will work it's just a race between the adding of new item and the selecting of it.

How can I go about it?


Solution

  • I gave Cactus's suggestion in the comments a try, and it turns out it couldn't been done (I'd have to bind changes in the middle of let block where the selection behavior, and the list behavior is, but they depend on each other).

    So I decided to start again from scratch but over-do it this time, and wrap the entire state in it's own data-type which the network will merely drive. So really all the network will do is call functions on the network according to events, and that's it. It turned out much superior imo, because there's no applicative-style mess, all the functionality is really just simple functions, and it's more modular (I could decide to just not use FRP at all for example, and the changes would be extremely minor -- just switch the firing with the functions; although I'd still have to find where to put the state, which would probably be something impure like IORef).

    It's so clean, it looks something similar to this:

    data DbState = DbState Database SelectedItem LastAction Etc Etc
    emptyState :: DbState
    stateRemove, stateAdd :: DbState -> DbState
    

    and the behavior is just:

    let bDb = accumB emptyState $ unions
          [stateAdd <$ eAddEntry
          ,stateRemove <$ eRemoveEntry
          ]
    

    Prior, I had length lines filled with lambdas, <$>, <*>, etc. all over.

    And now I just rectimate' and see the changes through that LastAction.
    I also added error-checking extremely trivially like that.