Search code examples
haskellmonadsreflex

Structuring a dynamic list of reflex-dom widgets/events according to numeric user input


I'm trying to create a dynamic list of widgets with the number of widgets determined by a numeric value from user input. Furthermore, each widget returns a click event. Here's what I'm using to get the user input:

settings :: MonadWidget t m => m (Dynamic t (Maybe Int))

Then I use this to generate a list of random number generators (The fact that these are values of RandomGen is not significant. They're just used for the content of each element, not the number of elements).:

split' :: RandomGen g => Int -> g -> [g]
-- ...

gs <- mapDyn (maybe (split' 1 g) (flip split' g)) =<< settings

Now I have gs :: (MonadWidget t m, RandomGen g) => Dynamic t [g]. One g for each widget. These widgets return Event values so I'll need to combine them (i.e. leftmost) then use that value with foldDyn somewhere.

go :: (MonadWidget t m, Random g) => g -> m (Event t MyType)
-- ...

clicked <- el "div" $ do
  -- omg
  xs <- simpleList gs go

  -- would like to eventually do this
  dynEvent <- mapDyn leftmost xs
  return $ switch (current dynEvent)

But so far I end up with xs :: Dynamic t [Dynamic t (m (Event t MyType))].

I think what I really need is to somehow make xs :: MonadWidget t m => Dynamic t [Event t MyType] instead but having some trouble getting there even with other functions aside from simpleList.


Solution

  • Your problem is that simpleList takes a Dynamic t [g] and (Dynamic t g -> m a). However, your go is g -> m (Event t MyType). So you need to create a better go:

    go2 :: (MonadWidget t m, RandomGen g) => Dynamic t g -> m (Event t MyType)
    go2 gDyn = do
        mapped <- mapDyn go gDyn
        dyned <- dyn mapped
        held <- hold never dyned
        return (switch held)
    

    Once you have this, it should be easier as simpleList gs go2 will return m (Dynamic t [Event t MyType]) and you should be able to mapDyn leftmost over it.

    This is not the most elegant solution, but that's the best I was able to find when I was trying something similar. I'm sure it could be extracted into some helper function.

    Note that I don't have a compiler with me, and typechecking this in my head is quite difficult, so if it doesn't work, write a comment. I'll have a look when I'm home with a compiler.