{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeOperators #-} -- | DSL/interpreter model for the logger module Imm.Logger where -- {{{ Imports import Imm.Prelude import Control.Monad.Trans.Free -- import Text.PrettyPrint.ANSI.Leijen -- }}} -- * Types data LogLevel = Debug | Info | Warning | Error deriving(Eq, Ord, Read, Show) instance Pretty LogLevel where pretty Debug = text "DEBUG" pretty Info = text "INFO" pretty Warning = text "WARNING" pretty Error = text "ERROR" -- | Logger DSL data LoggerF next = Log LogLevel Text next | GetLevel (LogLevel -> next) | SetLevel LogLevel next deriving(Functor) -- | Logger interpreter data CoLoggerF m a = CoLoggerF { logH :: LogLevel -> Text -> m a , getLevelH :: m (LogLevel, a) , setLevelH :: LogLevel -> m a } deriving(Functor) instance Monad m => PairingM (CoLoggerF m) LoggerF m where -- pairM :: (a -> b -> m r) -> f a -> g b -> m r pairM p (CoLoggerF l _ _) (Log level message next) = do a <- l level message p a next pairM p (CoLoggerF _ gl _) (GetLevel next) = do (l, a) <- gl p a (next l) pairM p (CoLoggerF _ _ sl) (SetLevel level next) = do a <- sl level p a next -- * Primitives log :: (Functor f, MonadFree f m, LoggerF :<: f) => LogLevel -> Text -> m () log level message = liftF . inj $ Log level message () getLogLevel :: (Functor f, MonadFree f m, LoggerF :<: f) => m LogLevel getLogLevel = liftF . inj $ GetLevel id setLogLevel :: (Functor f, MonadFree f m, LoggerF :<: f) => LogLevel -> m () setLogLevel level = liftF . inj $ SetLevel level () -- * Helpers logDebug, logInfo, logWarning, logError :: (Functor f, MonadFree f m, LoggerF :<: f) => Text -> m () logDebug = log Debug logInfo = log Info logWarning = log Warning logError = log Error