{-# LANGUAGE UndecidableInstances #-} module Reflex.Monad.Class ( MonadSwitch (..) , MonadReflex , module Reflex , module Reflex.Switching , module Reflex.Updated , module Control.Monad.Writer.Class ) where import Reflex import Reflex.Updated import Reflex.Switching import Data.Maybe import Data.Functor import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Control.Monad import Control.Monad.Reader import Control.Monad.Writer import Control.Monad.Writer.Class import Prelude -- | Constraint type to capture common usage together type MonadReflex t m = (Reflex t, MonadHold t m, MonadFix m) class (MonadReflex t m) => MonadSwitch t m | m -> t where -- | Map the result of an initial monadic action and updates and swap -- it out with a new one whenever the event provided fires. -- returns an Updated giving the initial value plus updates switchM :: Updated t (m a) -> m (Updated t a) switchM u = do m <- switchMapM (toMap (Just <$> u)) return $ fromJust <$> fromMap m -- | Similar to holdM but operating on a collection of widgets -- provided as an 'UpdatedMap'. -- switchM/switchM' can be implemented in terms of switchMapM -- therefore switchMapM is a minimal implementation. switchMapM :: Ord k => UpdatedMap t k (m a) -> m (UpdatedMap t k a) instance MonadSwitch t m => MonadSwitch t (ReaderT e m) where switchM u = do env <- ask lift $ switchM (flip runReaderT env <$> u) switchMapM um = do env <- ask lift . switchMapM $ flip runReaderT env <$> um instance (MonadSwitch t m, SwitchMerge t w) => MonadSwitch t (WriterT w m) where switchM u = do (a, w) <- lift $ split <$> switchM (runWriterT <$> u) tell =<< switching' w return a switchMapM um = do (a, w) <- lift $ split <$> switchMapM (runWriterT <$> um) tell =<< switchMerge' w return a -- A few conversions for switchM in terms of switchMapM maybeToMap :: Maybe a -> Map () a maybeToMap Nothing = mempty maybeToMap (Just a) = Map.singleton () a mapToMaybe :: Map () a -> Maybe a mapToMaybe m = listToMaybe $ Map.elems m toMap :: Reflex t => Updated t (Maybe a) -> UpdatedMap t () a toMap (Updated initial e) = UpdatedMap (maybeToMap initial) (Map.singleton () <$> e) fromMap :: Reflex t => UpdatedMap t () a -> Updated t (Maybe a) fromMap (UpdatedMap initial e) = Updated (mapToMaybe initial) (fmapMaybe mapToMaybe e) {-# ANN module "HLint: ignore Use import/export shortcut" #-}