
I've been having network problems, and in addition, I usually use gmane to access this list, but Sebastian and Yitzchak's messages never turned up there. On 2009-08-24 at 09:59+0200 Sebastian Fischer wrote:
Add check function to Control.Monad
check :: (MonadPlus m) => (a -> Bool) -> a -> m a check p a | p a = return a | otherwise = mzero
I agree that such a function is occasionally useful. But I doubt your rationale:
Rationale: [...]
but check is clearly more generally useful than guard. (guard = flip (check . const) ())
This is a bit like saying that concatMap is more generally useful than map and concat because:
I think I wasn't clear. When I said "clearly" I thought that the general usefulness was clear; the remark about guard was an "and" rather than a "because". What makes it clear to me is the types: check is more polymorphic in the sense that it has a type variable where guard has ().
map f = concatMap ((:[]).f) concat = concatMap id
Although this is correct, map and concat are smaller pieces that can be easily combined to concatMap:
concatMap f = concat . map f
So the question is whether check is useful enough to be included as a shortcut for a combination of simpler primitives (as was decided for concatMap).
Well, while I agree with the general principle, (and have argued for it strongly in the past), I don't agree with the way you are using "simple" here. When designing a library, one should choose the primitives so that future definitions are simple, both in the complexity of the terms needed to define them and in the thought needed to define them, rather than the simplicity of definition of the primitives themselves. The reason that I suggested check is that it seems to me that it gives both of those things in a way that guard doesn't (and people may have to work a bit when weighing this, owing to the long-standing familiarity of guard). The reason I didn't suggest removal of guard was that long-standing familiarity. To my mind, MonadPlus m => m () is a very specific and rather peculiar type (consider [()], for example) and I think guard suggests a rather imperative outlook because of this. Getting from m () to Maybe Char strikes me as a longer thought process than getting from m a to Maybe Char.
so we would expect a function
mfilter = (join .) . liftM . check
to be useful. Should that also be added?
I would not object and prefer this definition:
mfilter f m = m >>= check f
It seems simpler.
I agree. The equation above was just the derivation. Jón -- Jón Fairbairn Jon.Fairbairn at cl.cam.ac.uk