2
main = mainWidget $
  el "div" $ do
    let fileInputConfig = FileInputConfig (constDyn Map.empty)
    fi <- fileInput fileInputConfig

    let uploads   :: Dynamic t [File]            = value fi
    upload        :: Dynamic t (Maybe File)      <- (return . fmap headMay) uploads
    getNameAction :: Dynamic t (Maybe (IO Text)) <- (return . fmap (getNameText <$>)) upload
    filename      :: Dynamic t (Maybe Text)      <- (return . fmap (unsafePerformIO <$>)) getNameAction

    el "div" $ dynText (show <$> filename)
  return ()
  where getNameText :: MonadIO m => File -> m Text
        getNameText = getName

I did my best to play connect-the-dots with the types but I couldn't find a path out without using unsafePerformIO. I think it's safe in this case, but obviously there are other similar things you might want to do that would not be safe.

John
  • 14,944
  • 12
  • 57
  • 57
  • 1
    You've got to get that `IO` to the outer layer of `Dynamic t (Maybe (IO Text))` so you can bind it. `sequenceA` is the general way to commute an applicative outward, e.g. `sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)`, i.e. `sequenceA :: Maybe (IO a) -> IO (Maybe a)`. But that would require `Dynamic t` to be traversable, and I don't know if it is. – luqui May 26 '17 at 08:19
  • sequenceA does get the IO to the outside (ie I end up with a `Dynamic t (IO (Maybe Text))`) but I'm still unsure how turn that into a `Dynamic t (Maybe Text)` without `unsafePerformIO`. – John May 26 '17 at 22:51
  • Yeah, what is `Dynamic t`, what library are you working with? – luqui May 26 '17 at 23:58
  • Reflex/Reflex.Dom (as mentioned in the title). – John May 27 '17 at 04:13

1 Answers1

4

For things like this, you usually need performEvent. I don't have compiler/REPL at hand to provide more detail, and the function is sort-of hidden behind some typeclass hackery (https://github.com/reflex-frp/reflex/blob/9575a5660334fb8a617da1cd9aa1b522e8e4ddb7/src/Reflex/PerformEvent/Class.hs), but the gist of it is that if you have an event carrying IO, then you can run it wherever this event occurs.

Now, you've got the Dynamic, but you can

  • extract the event from it
  • maybe it doesn't need to be Dynamic (it doesn't make sense, as you don't want to peek at the IO value)
Bartosz
  • 3,318
  • 21
  • 31