kazu-yamamoto / logger

A fast logging system for Haskell
159 stars 68 forks source link

Functor & Applicative instance of LoggingT destroys Haxl Parallelism #125

Closed mageshb closed 7 years ago

mageshb commented 7 years ago

Currently Functor & Applicative instance of LoggingT is defined in terms of its Monad implementation. So when LoggingT is layered over Haxl, parallelism that we used to get via'a Haxl's Applicative instance is lost.

Reimplementing Functor & Applicative instance as below solves the issue.

newtype LogT m a = LogT {runLogT :: Log.LoggingT m a}
                 deriving (MonadIO, Log.MonadLogger, Log.MonadLoggerIO)

runLoggingT :: LogT m a
            -> ((Log.Loc -> Log.LogSource -> Log.LogLevel -> Log.LogStr -> IO ()) -> m a)
runLoggingT = Log.runLoggingT . runLogT

pattern LoggingT :: ((Log.Loc -> Log.LogSource -> Log.LogLevel -> Log.LogStr -> IO ()) -> m a)
                 -> LogT m a
pattern LoggingT log = LogT (Log.LoggingT log)

instance Functor m => Functor (LogT m) where
  fmap f (LogT logger) = LogT $ Log.LoggingT $ \loggerFn -> fmap f $ (Log.runLoggingT logger) loggerFn
  {-# INLINE fmap #-}

instance Applicative m => Applicative (LogT m) where
  pure = LogT . Log.LoggingT . const . pure
  {-# INLINE pure #-}
  (LogT loggerF) <*> (LogT loggerA) = LogT $ Log.LoggingT $ \loggerFn -> (Log.runLoggingT loggerF) loggerFn <*> (Log.runLoggingT loggerA) loggerFn
  {-# INLINE (<*>) #-}

instance Monad m => Monad (LogT m) where
  return = pure
  {-# INLINE return #-}
  (LogT logger) >>= k = LogT (logger >>= runLogT . k)
  {-# INLINE (>>=) #-}

instance MonadTrans LogT where
  lift = LogT . Log.LoggingT . const
  {-# INLINE lift #-}

Is there a possiblity that we can reimplement Functor & Applicative instance of LoggingT to not to fallback on it's Monad instance?

snoyberg commented 7 years ago

Sounds reasonable, want to send a PR?

On Thu, Mar 16, 2017, 4:43 PM Magesh notifications@github.com wrote:

Currently Functor & Applicative instance of LoggingT is defined in terms of its Monad implementation. So when LoggingT is layered over Haxl, parallelism that we used to get via'a Haxl's Applicative instance is lost.

Reimplementing Functor & Applicative instance as below solves the issue.

newtype LogT m a = LogT {runLogT :: Log.LoggingT m a} deriving (MonadIO, Log.MonadLogger, Log.MonadLoggerIO) runLoggingT :: LogT m a -> ((Log.Loc -> Log.LogSource -> Log.LogLevel -> Log.LogStr -> IO ()) -> m a) runLoggingT = Log.runLoggingT . runLogT

pattern LoggingT :: ((Log.Loc -> Log.LogSource -> Log.LogLevel -> Log.LogStr -> IO ()) -> m a) -> LogT m a pattern LoggingT log = LogT (Log.LoggingT log) instance Functor m => Functor (LogT m) where fmap f (LogT logger) = LogT $ Log.LoggingT $ \loggerFn -> fmap f $ (Log.runLoggingT logger) loggerFn {-# INLINE fmap #-} instance Applicative m => Applicative (LogT m) where pure = LogT . Log.LoggingT . const . pure {-# INLINE pure #-} (LogT loggerF) <> (LogT loggerA) = LogT $ Log.LoggingT $ \loggerFn -> (Log.runLoggingT loggerF) loggerFn <> (Log.runLoggingT loggerA) loggerFn {-# INLINE (<*>) #-} instance Monad m => Monad (LogT m) where return = pure {-# INLINE return #-} (LogT logger) >>= k = LogT (logger >>= runLogT . k) {-# INLINE (>>=) #-} instance MonadTrans LogT where lift = LogT . Log.LoggingT . const {-# INLINE lift #-}

Is there a possiblity that we can reimplement Functor & Applicative instance of LoggingT to not to fallback on it's Monad instance?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/kazu-yamamoto/logger/issues/125, or mute the thread https://github.com/notifications/unsubscribe-auth/AADBB9pax9uaqQFVeNRpFhD3rRD3jlmtks5rmUp6gaJpZM4MfZof .

mageshb commented 7 years ago

Sure. I will send a PR