-- | This module defines 'Requester', which indicates that an action can make -- requests and receive responses to them. Typically, this is used for things -- like a WebSocket, where it's desirable to collect many potential sources of -- events and send them over a single channel, then distribute the results back -- out efficiently to their original request sites. {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE RecursiveDo #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} #ifdef USE_REFLEX_OPTIMIZER {-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-} #endif module Reflex.Requester.Class ( Requester (..) , withRequesting , requestingIdentity ) where import Control.Monad.Identity import Control.Monad.Reader import qualified Control.Monad.State.Lazy as Lazy import Control.Monad.State.Strict import Reflex.Class -- | A 'Requester' action can trigger requests of type @Request m a@ based on -- 'Event's, and receive responses of type @Response m a@ in return. Note that -- the @a@ type can vary within the 'Requester' action, but will be linked for a -- given request. For example, if @Request m@ is 'IO' and @Response m@ is -- 'Identity', then 'requestingIdentity' has the same type as -- 'Reflex.PerformEvent.Class.performEvent'. class (Reflex t, Monad m) => Requester t m | m -> t where -- | The type of requests that this 'Requester' can emit type Request m :: * -> * -- | The type of responses that this 'Requester' can receive type Response m :: * -> * -- | Emit a request whenever the given 'Event' fires, and return responses in -- the resulting 'Event'. requesting :: Event t (Request m a) -> m (Event t (Response m a)) -- | Emit a request whenever the given 'Event' fires, and ignore all responses. requesting_ :: Event t (Request m a) -> m () instance Requester t m => Requester t (ReaderT r m) where type Request (ReaderT r m) = Request m type Response (ReaderT r m) = Response m requesting = lift . requesting requesting_ = lift . requesting_ instance Requester t m => Requester t (StateT s m) where type Request (StateT s m) = Request m type Response (StateT s m) = Response m requesting = lift . requesting requesting_ = lift . requesting_ instance Requester t m => Requester t (Lazy.StateT s m) where type Request (Lazy.StateT s m) = Request m type Response (Lazy.StateT s m) = Response m requesting = lift . requesting requesting_ = lift . requesting_ -- | Emit a request whenever the given 'Event' fires, and unwrap the responses -- before returning them. @Response m@ must be 'Identity'. requestingIdentity :: (Requester t m, Response m ~ Identity) => Event t (Request m a) -> m (Event t a) requestingIdentity = fmap coerceEvent . requesting withRequesting :: (Requester t m, MonadFix m) => (Event t (Response m a) -> m (Event t (Request m a), r)) -> m r withRequesting f = do rec response <- requesting request (request, result) <- f response return result