1

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?

MasterMastic
  • 20,711
  • 12
  • 68
  • 90
  • Could you simply multiply your `[Entry]` with something else in its `accumB` that tells you the source of the last change? So you'd get `([Entry], ReasonItChanged)` with some appropriate datatype `data ReasonItChanged = UserAdded | UserRemoved`. – Cactus Jul 02 '15 at 04:05
  • @Cactus Err.. well I really wanted to avoid add that complexity, but if FRP/reactive-banana doesn't have a better way, I'll resort. I'll try it nevertheless. Thanks a lot. – MasterMastic Jul 02 '15 at 04:46
  • 1
    Have you looked at the [CRUD.hs](https://wiki.haskell.org/Reactive-banana/Examples#crud) example? It deals with a similar situation. The idea is that currently selected item comes from two sources: User clicks in the list box, and changes from within the program. The easiest way to go about it is to treat the latter as "suggestions", but the former as "definitive". – Heinrich Apfelmus Jul 02 '15 at 08:37

1 Answers1

2

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.

MasterMastic
  • 20,711
  • 12
  • 68
  • 90