I have defined a datatype RuleFile and I writing a function that examines a Rulefile with a number of predicates, accumulating warning strings as it goes along.
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 off-the-shelf haskell function for <process>? Or maybe I'm not thinking about this in an idiomatic haskell way, and there's some other recommended approach? I'm using Control.Monad.Except for errors, but my current thinking is I want to treat warnings separately and output the messages on stderr.
Later on, I'll use it with something like ...
main :: IO ()
main = do
<some stuff>
ruleFiles <- <produce them>
mapM (hPutStr stderr) (map rfWarnings ruleFiles)
<other stuff>
You could use a Writer for this:
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 compose rfWarnings from smaller pieces, e.g.
rfWarnings rf = execWriter $ do
unless (looksOK rf) $ tell "Completely b0rken!"
mapM_ partWarning (parts rf)
and also, I'd rather use unless than when because I think describing the correct state is better than describing the incorrect one.
Not sure if this works for your application – but, an idiomatic thing might be to change the type of your predicates: rather than a fixed string and a function that returns Bool (but in the Nothing case you don't actually need the string), use only a function – which returns Maybe String. Then what you're asking about becomes very simple: apply all functions in a list to a given argument, and gather the Just values.
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 stuff in the Maybe MonadPlus, you can define an operator that links ordinary predicates directly to the strings you want them to yield:
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
Looks perhaps even nicer the other way around:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With