可选参数以及case语句

时间:2017-01-19 03:53:28

标签: haskell maybe

我了解了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

3 个答案:

答案 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!