在我实现它之前寻找一个标准的Haskell成语

时间:2015-06-28 20:56:39

标签: haskell

我已经定义了一个数据类型RuleFile,并且我编写了一个函数来检查具有多个谓词的Rulefile,并在它出现时累积警告字符串。

rfWarnings :: RuleFile -> [String]
rfWarnings rf = let warnings = [((\rf -> length (neigh rf) > 3), "warning: unknown extra information in the neighborhood, discarding it and moving on"),
                               <more warnings> ]
                in <process> warnings

<process>是否有一些现成的haskell功能?或者也许我没有以惯用的haskell方式思考这个问题,还有其他一些推荐的方法吗?我使用Control.Monad.Except来表示错误,但我目前的想法是我想单独处理警告并在stderr上输出消息。

稍后,我将使用类似......

的东西
main :: IO ()
main = do
 <some stuff>
 ruleFiles <- <produce them>
 mapM (hPutStr stderr) (map rfWarnings ruleFiles)
 <other stuff>

3 个答案:

答案 0 :(得分:4)

不确定这是否适用于您的应用程序 - 但是,惯用的事情可能是更改谓词的类型:而不是固定字符串和returns Bool的函数(但在Nothing中如果您实际上不需要字符串,请仅使用 函数 - 返回Maybe String。然后你要问的内容变得非常简单:将列表中的所有函数应用于给定的参数,并收集Just值。

rfWarnings' :: RuleFile -> [String]
rfWarnings' rf = catMaybes $ map ($rf) warnings
 where warnings = [ \rf -> guard (length (neigh rf) > 3) >> return
                             "warning: unknown extra information in the neighborhood, discarding it and moving on"
                  , {-more warnings-}
                  ]

为避免在Maybe guard中重复此MonadPlus内容,您可以定义一个将普通谓词直接链接到您希望它们产生的字符串的运算符:

 where warnings = [ (\rf -> length (neigh rf) > 3) ==>
                             "warning: unknown extra information in the neighborhood, discarding it and moving on"
                  , {-more warnings-}
                  ]
       pred ==> str = guard pred >> return str

看起来或许更好看反过来:

 where warnings = [ "warning: unknown extra information in the neighborhood, discarding it and moving on"
                      \<= \rf -> length (neigh rf) > 3
                  , {-more warnings-}
                  ]
       str \<= pred = guard pred >> return str

答案 1 :(得分:4)

您可以使用Writer

import Control.Monad.Writer

rfWarnings rf = execWriter $ do
    unless (length (neigh rf) <= 3) $ tell "Too much neigh!"
    unless (isFrobulastic rf) $ tell "Frobulation mismatch!"

这样做的好处是可以很容易地从较小的部分组成rfWarnings,例如

rfWarnings rf = execWriter $ do
  unless (looksOK rf) $ tell "Completely b0rken!"
  mapM_ partWarning (parts rf)

而且,我宁愿使用unless而不是when,因为我认为描述正确的状态比描述错误状态要好。

答案 2 :(得分:3)

rfWarnings rf = let warnings = [((\rf -> length (neigh rf) > 3), "warning: ..."),
                                <more warnings> ]
                in [ message | (predicate, message) <- warnings, predicate rf ]

甚至,删除lambda,

rfWarnings rf = let warnings = [(length (neigh rf) > 3, "warning: ..."),
                                <more warnings> ]
                in [ message | (predicate, message) <- warnings, predicate ]

甚至(有点神秘)

rfWarnings rf = let warnings = [(length (neigh rf) > 3, "warning: ..."),
                                <more warnings> ]
                in [ message | (True, message) <- warnings ]

或甚至(更短但可读性更低)

rfWarnings rf = let warnings = [(length (neigh rf) > 3, "warning: ..."),
                                <more warnings> ]
                in map snd $ filter fst warnings