我了解了hslogger here。
initLogging :: Priority -> IO ()
initLogging level = do
stdOutHandler <- streamHandler stdout level >>= \lh -> return $
setFormatter lh (simpleLogFormatter "[$prio:$loggername:$time] $msg")
updateGlobalLogger rootLoggerName (setLevel level . setHandlers [stdOutHandler])
我想制作一个&#34; quicklog&#34;只需要较少的输入即可用于调试的函数:如果将logtype指定为&#34; I&#34;,则使用infoM
,如果指定为&#34; D&#34;,则使用{{ 1}}等,如果没有指定loglevel,则默认为debugM
。
我可以制作一个能满足我需要的版本:
INFO
这有效:
qLog :: String -> String -> IO ()
qLog l msg = log' "" msg where
log' "I" msg = infoM "" msg
log' "D" msg = debugM "" msg
log' "E" msg = errorM "" msg
log' "W" msg = warningM "" msg
log' _ msg = infoM "" msg
但如果没有指定级别,我就无法选择infoM,la:
λ> qlog "D" "Thing!"
[DEBUG::2017-01-18 20:38:19 EST] Thing!
λ> qlog "I" "Thing!"
[INFO::2017-01-18 20:38:19 EST] Thing!
这简直失败了,期待&#34;事情!&#34;是可选的loglevel,而不是msg参数。我认为这需要一个Maybe来传达第一个论点可能根本不存在,但似乎无法做到正确。以下是我的尝试:
λ> qlog "Thing!"
[INFO::2017-01-18 20:38:19 EST] Thing!
或者
qLog2 :: Maybe String -> String -> IO ()
qLog2 l msg = case l msg of
(Just "D") msg -> debugM "" msg
(Just "I") msg -> infoM "" msg
Nothing msg -> infoM "" msg
我似乎无法在类型声明+ qLog3 :: Maybe String -> String -> IO ()
qLog3 l msg
| Just "D" msg = debugM "" msg
| Just "I" msg = infoM "" msg
| Nothing msg = infoM "" msg
或case
中充分说明如何进行组合。
更新1
guard
给我:
qLog4 "D" msg = debugM "" msg
qLog4 "I" msg = infoM "" msg
qLog4 msg = infoM "" msg
更新2:
在我通过here
找出可选参数部分时放弃案例Equations for ‘qLog4’ have different numbers of arguments
答案 0 :(得分:3)
qLog2
的固定版本将是
qLog2 :: Maybe String -> String -> IO ()
qLog2 l msg =
case l of
Just "D" -> debugM "" msg
Just "I" -> infoM "" msg
Nothing -> infoM "" msg
如果您要重载qlog
以获取该级别的可选参数,则需要使用类型类。这个功能很烦人。如果您希望此类型qlog "I"
或String -> IO ()
,则在撰写IO ()
时会出现歧义。也许您为信息级别创建了一个日志功能,或者您正在记录消息“I”
答案 1 :(得分:3)
您只需要对l
参数进行案例分析:
qLog :: Maybe String -> String -> IO ()
qLog l msg = case l of
Just "D" -> debugM "" msg
Just "I" -> infoM "" msg
-- etc.
Nothing -> infoM "" msg
(如果您确实需要对msg
进行案例分析,您可以通过元组 - case (l, msg) of
来完成 - 正如Alec建议的那样,或者只是用多个方程替换case语句。)
无关建议:您可以使用自定义类型来表示日志级别,而不是字符串。这既可以使事情更清晰,又可以消除将"G"
或"foobar"
作为日志级别传递的风险。
-- Feel free to use less terse names.
data LogLevel = D | I | W | E
deriving (Eq, Show)
qLog :: Maybe LogLevel -> String -> IO ()
qLog l msg = case l of
Just D -> debugM "" msg
Just I -> infoM "" msg
Just W -> warningM "" msg
Just E -> errorM "" msg
Nothing -> infoM "" msg
你也可以分解出重复性的很大一部分:
-- I added a few superflous parentheses to emphasise what is going on.
qLog :: Maybe LogLevel -> String -> IO ()
qLog ml msg = case ml of
Just l -> (fLog l) "" msg
Nothing -> infoM "" msg
where
fLog :: LogLevel -> (String -> String -> IO ())
fLog l = case l of
D -> debugM
I -> infoM
W -> warningM
E -> errorM
或者,使用maybe
整齐地消除了可能性:
GHCi> :t maybe
maybe :: b -> (a -> b) -> Maybe a -> b
-- There are also some superflous parentheses here.
qLog :: Maybe LogLevel -> String -> IO ()
qLog ml msg = (maybe infoM fLog ml) "" msg
where
fLog :: LogLevel -> (String -> String -> IO ())
fLog l = case l of
D -> debugM
I -> infoM
W -> warningM
E -> errorM
答案 2 :(得分:2)
如果我理解你的问题是正确的,那么你可以这样做:
{-# LANGUAGE GADTs #-}
qlog :: LogResult a => a
qlog = log' []
class LogResult a where
log' :: [LogArg] -> a
class IsLogArgument a where
toLogArg :: a -> LogArg
data LogArg = LogLevel LogLevel
| LogMessage String
data LogLevel = D | I | W | E
instance IsLogArgument LogLevel where
toLogArg = LogLevel
instance (a ~ Char) => IsLogArgument [a] where
toLogArg = LogMessage
instance (IsLogArgument arg, LogResult result) => LogResult (arg -> result) where
log' args arg = log' ((toLogArg arg) : args)
instance (a ~ ()) => LogResult (IO a) where
log' args = tell "" msg
where
tell = case level of
D -> debugM
I -> infoM
W -> warningM
E -> errorM
level = fromMaybe I $ look logLevel
msg = fromMaybe "No message" $ look logMessage
logLevel (LogLevel x) = Just x
logLevel _ = Nothing
logMessage (LogMessage x) = Just x
logMessage _ = Nothing
look = listToMaybe . catMaybes . flip map args
和
λ> qlog D "Thing!"
[DEBUG::2017-01-18 20:38:19 EST] Thing!
λ> qlog "Thing!"
[INFO::2017-01-18 20:38:19 EST] Thing!