I really hope I haven't gone down a dead-end here. I have a Behaviour that gives the currently selected Color, and the current mouse coordinates, then carries out a task when the mouse is clicked. That task involves looking at a list and then updating the values in that list, for it to be retrieved later. The fact that I can "store" the selected color gives me hope that storing a list can be done in a similar manner. I'm just at a dead end and not sure how to solve this. Would really appreciate some help.
-- There is a Blue button and a Red button on our UI. Whichever
-- button was clicked last is our current color selection.
colorRedSelected = const ColorRed <$ UI.click redButton
colorBlueSelected = const ColorBlue <$ UI.click blueButton
-- we combine both the above Events to create a new one that tells us the current selected color
colorSelected = unionWith const colorRedSelected colorBlueSelected
-- accumulate values for our Behaviour, starting with ColorRed selected by default
colorMode <- accumB ColorRed modeEvent
-- create a Behaviour
mouseCoordinate <- stepper (0,0) $ UI.mousemove canvas
-- want to start with the list [1,2,3,4], but this value should change later.
-- I have 'never' here, as I don't know what else to put here yet.
listState <- accumB ([1,2,3,4]) never
-- Combine the Behaviours, we now have a tuple (chosenColorMode, mouseCoordinateTuple, savedList)
let choices = (,,) <$> colorMode <*> mouseCoordinate <*> listState
-- Apply the event (of the user clicking the canvas) to the Behaviour,
-- creating a new Event that returns the above tuple when it fires
makeChoice = choices <@ UI.click canvas
onEvent makeChoice $ \(colorMode, (x,y), savedList) -> do
...
-- in this block we use the savedList, and generate a newList.
-- I want to update the choicePosition behaviour so that the newList
-- replaces the old savedList.
Full credit to this response from duplode, I'll just go through how it was solved:
Let's say we have a function that modifies a list somehow, depending on some value. How/why updateMyList
modifies the list doesn't really matter for this explanation, we just need to know its type. For this example, we'll say the value that determines how the list changes is a mouse coordinate tuple (x, y), which we'll pass as its first parameter:
updateMyList :: (Double, Double) -> [Integer] -> [Integer]
updateMyList (x, y) oldList = ...
If we have an Event that tells us the mouse coordinates when the user clicks:
mouseCoords :: Behavior (Double, Double)
mouseCoords <- stepper (0,0) $ UI.mousemove canvas
mouseClicked :: Event (Double, Double)
mouseClicked = mouseCoords <@ UI.click canvas -- this is the Event we need
What we need to do is fmap
the list-updating function onto mouseClicked
:
listChangeEvent = fmap updateMyList mouseClicked
So we've created a new Event: when mouseClicked
is triggered, the mouse coordinates are passed as the first parameter to updateMyList
, and that is the value of our new Event at that timestamp. But this is a partially applied function, updateMyList
still requires an [Integer]
as a parameter, so as a result, listChangeEvent
has the following type:
listChangeEvent :: Event ([Integer] -> [Integer])
Now, this is the clever part: if we use accumB
and specify the starting accumulator (i.e. our starting list, [1,2,3,4]
), and then also use the above listChangeEvent
as the Event accumB
takes its value from:
listState <- accumB ([1,2,3,4]) listChangeEvent
Then that accumulator is what will be passed to the function in Event ([Integer] -> [Integer])
. Meaning the first time the listChangeEvent
triggers, updateMyList
will be called with:
updateMyList (x, y) [1,2,3,4] -- (x, y) being the mouse coordinates at that time
And the result of that becomes the new accumulator value in listState
, and that new list will be used as the parameter to updateMyList
the next time listChangeEvent
triggers, and so on.
We can use this for anything at all, it doesn't necessarily have to be a list that we're modifying. This just gives us a way to initialize a Behavior with a value, and that we can specify exactly how the next value of the Behavior is derived, by creating a function that is equivalent to updateMyList
.