Что я могу сделать, чтобы устранить unsafePerformIO в этом коде Reflex.Dom?

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

Я изо всех сил старался играть в «соедини точки» с типами, но не мог найти выход без использования unsafePerformIO. Я думаю, что в данном случае это безопасно, но, очевидно, есть и другие подобные вещи, которые вы, возможно, захотите сделать, но которые не были бы безопасными.


person John    schedule 26.05.2017    source источник
comment
Вы должны поместить этот IO во внешний слой Dynamic t (Maybe (IO Text)), чтобы вы могли его связать. sequenceA - это общий способ замены аппликативного падежа наружу, например. sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a), то есть sequenceA :: Maybe (IO a) -> IO (Maybe a). Но для этого потребуется, чтобы Dynamic t можно было пройти, и я не знаю, так ли это.   -  person luqui    schedule 26.05.2017
comment
sequenceA выводит ввод-вывод наружу (т.е. я получаю Dynamic t (IO (Maybe Text))), но я все еще не уверен, как превратить это в Dynamic t (Maybe Text) без unsafePerformIO.   -  person John    schedule 27.05.2017
comment
Ага, что такое Dynamic t, с какой библиотекой ты работаешь?   -  person luqui    schedule 27.05.2017
comment
Рефлекс/Рефлекс.Дом (как указано в названии).   -  person John    schedule 27.05.2017


Ответы (1)


Для подобных вещей обычно требуется performEvent. У меня нет под рукой компилятора/REPL, чтобы предоставить более подробную информацию, и функция как бы скрыта за каким-то хакерством с классом типов (https://github.com/reflex-frp/reflex/blob/9575a5660334fb8a617da1cd9aa1b522e8e4ddb7/src/Reflex/PerformEvent/Class.hs) , но суть в том, что если у вас есть событие, несущее IO, то вы можете запускать его везде, где это событие происходит.

Теперь у вас есть Dynamic, но вы можете

  • извлечь из него событие
  • возможно, он не должен быть динамическим (это не имеет смысла, так как вы не хотите заглядывать в значение IO)
person Bartosz    schedule 26.05.2017
comment
Спасибо, сейчас изучаю performEvent. - person John; 27.05.2017