Looking for a standard Haskell icon before I embody it
I have defined a datatype RuleFile
and I am writing a function that explores RuleFile
with a number of predicates, accumulating warning lines as they go.
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
Is there some kind of out-of-the-box haskell function for <process>
? Or maybe I don't think about it by the idiomatic haskell method, and is there another recommended approach? I am using Control.Monad.Except
for errors, but my current thinking is that I want to handle warnings separately and output messages to stderr.
Later I will use it with something like ...
main :: IO ()
main = do
<some stuff>
ruleFiles <- <produce them>
mapM (hPutStr stderr) (map rfWarnings ruleFiles)
<other stuff>
source to share
Not sure if this works for your application - but, the idiomatic thing might be to change the type of your predicates: instead of a fixed string and a function that returnsBool
(but in case Nothing
you don't really need a string), use only the function - that returns Maybe String
. Then what you are asking for becomes very simple: apply all the functions in the list to the given argument and collect the values 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-}
]
To avoid repeating this guard
in Maybe
MonadPlus
, you can define an operator that binds regular predicates directly to the strings you want:
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
It looks like it's even better:
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
source to share
To do this, you can use Writer
:
import Control.Monad.Writer
rfWarnings rf = execWriter $ do
unless (length (neigh rf) <= 3) $ tell "Too much neigh!"
unless (isFrobulastic rf) $ tell "Frobulation mismatch!"
This has the advantage that it is very easy to put together rfWarnings
smaller pieces, for example.
rfWarnings rf = execWriter $ do
unless (looksOK rf) $ tell "Completely b0rken!"
mapM_ partWarning (parts rf)
and also, I would rather use unless
than when
because I think that describing the correct state is better than describing the wrong one.
source to share
rfWarnings rf = let warnings = [((\rf -> length (neigh rf) > 3), "warning: ..."),
<more warnings> ]
in [ message | (predicate, message) <- warnings, predicate rf ]
or even by removing the lambda,
rfWarnings rf = let warnings = [(length (neigh rf) > 3, "warning: ..."),
<more warnings> ]
in [ message | (predicate, message) <- warnings, predicate ]
or even (a little more critical)
rfWarnings rf = let warnings = [(length (neigh rf) > 3, "warning: ..."),
<more warnings> ]
in [ message | (True, message) <- warnings ]
or even (shorter but less readable)
rfWarnings rf = let warnings = [(length (neigh rf) > 3, "warning: ..."),
<more warnings> ]
in map snd $ filter fst warnings
source to share