darcs patch: Add justIf to Data.Maybe

Hi,
I propose the attached change, with a discussion timeframe until end of
September. The corresponding ticket is
http://hackage.haskell.org/trac/ghc/ticket/3446
Thanks,
Joachim
Fri Aug 21 19:17:12 CEST 2009 Joachim Breitner

Joachim Breitner
Hi,
I propose the attached change, with a discussion timeframe until end of September. The corresponding ticket is http://hackage.haskell.org/trac/ghc/ticket/3446
Thanks, Joachim
I have been meaning to get round to proposing check for Data.Monad:
check :: (MonadPlus m) => (a -> Bool) -> a -> m a check p a | p a = return a | otherwise = mzero
Now justIf = flip (check . const) So I suggest that it would be better to add check first(, and then possibly switch the order of arguments to justIf). -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk

Hi, Am Samstag, den 22.08.2009, 10:13 +0100 schrieb Jon Fairbairn:
Joachim Breitner
writes: I propose the attached change, with a discussion timeframe until end of September. The corresponding ticket is http://hackage.haskell.org/trac/ghc/ticket/3446
Thanks, Joachim
I have been meaning to get round to proposing check for Data.Monad:
check :: (MonadPlus m) => (a -> Bool) -> a -> m a check p a | p a = return a | otherwise = mzero
Now justIf = flip (check . const)
So I suggest that it would be better to add check first(, and then possibly switch the order of arguments to justIf).
are you proposing that, if check is available, no justIf is needed in the libraries? Or are you just proposing a different implementation? Greetings, Joachim -- Joachim Breitner e-Mail: mail@joachim-breitner.de Homepage: http://www.joachim-breitner.de ICQ#: 74513189 Jabber-ID: nomeata@joachim-breitner.de

Joachim Breitner
Hi,
Am Samstag, den 22.08.2009, 10:13 +0100 schrieb Jon Fairbairn:
Joachim Breitner
writes: I propose the attached change, with a discussion timeframe until end of September. The corresponding ticket is http://hackage.haskell.org/trac/ghc/ticket/3446
Thanks, Joachim
I have been meaning to get round to proposing check for Data.Monad:
check :: (MonadPlus m) => (a -> Bool) -> a -> m a check p a | p a = return a | otherwise = mzero
Now justIf = flip (check . const)
So I suggest that it would be better to add check first(, and then possibly switch the order of arguments to justIf).
are you proposing that, if check is available, no justIf is needed in the libraries?
I wouldn't be proposing that, having promised not to post on the topic of naming short functions for ten years.
Or are you just proposing a different implementation?
I /am/ proposing that. I suppose I have to work out how to make a proper proposal for the addition of check? -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk

Joachim Breitner
are you proposing that, if check is available, no justIf is needed in the libraries? Or are you just proposing a different implementation?
For the record, I am opposed to justIf on the grounds that it is a specialisation of something that should be typed at MonadPlus (and which would consequently have to have a different name). -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk

On Sat, 2009-08-22 at 10:18 +0200, Joachim Breitner wrote:
Hi,
I propose the attached change
Fri Aug 21 19:17:12 CEST 2009 Joachim Breitner
* Add justIf to Data.Maybe
justIf :: a -> Bool -> Maybe a justIf x True = Just x justIf x False = Nothing Which apparently is intended to be used like: v `justIf` a Another instance of this idiom, this one from Cabal, is check :: Bool -> PackageCheck -> Maybe PackageCheck check False _ = Nothing check True pc = Just pc which generalises to check :: Bool -> a -> Maybe a check False _ = Nothing check True x = Just x which is used without `back ticks` like: check (not (null deprecatedExtensions)) $ PackageDistSuspicious $ "Deprecated extensions: " ++ {- some fairly big expression -} In this use case the result is typically a lot bigger than the condition, so the condition goes first rather than last. As Jón was suggesting we might want to generalise to MonadPlus rather than putting it in Data.Maybe, it becomes rather similar to the existing function 'guard': guard :: MonadPlus m => Bool -> m () guard True = return () guard False = mzero check :: MonadPlus m => Bool -> a -> m a check True x = return x check False _ = mzero Using a Bool for the condition is a tad more general than a predicate like: check :: MonadPlus m => (a -> Bool) -> a -> m a In particular, the use case in Cabal does not fit the predicate pattern because the condition is not a condition on the value being returned but on something else in the environment. BTW, I also don't want to take too strong a position on the name ;-) Duncan

Duncan Coutts
On Sat, 2009-08-22 at 10:18 +0200, Joachim Breitner wrote:
Hi,
I propose the attached change
Fri Aug 21 19:17:12 CEST 2009 Joachim Breitner
* Add justIf to Data.Maybe
As Jón was suggesting we might want to generalise to MonadPlus rather than putting it in Data.Maybe, it becomes rather similar to the existing function 'guard':
[...] some alpha conversion
checkA :: MonadPlus m => Bool -> a -> m a checkA True x = return x checkA False _ = mzero
Using a Bool for the condition is a tad more general than a predicate like:
checkB :: MonadPlus m => (a -> Bool) -> a -> m a
I'd say the generality comparison goes the other way:
In particular, the use case in Cabal does not fit the predicate pattern because the condition is not a condition on the value being returned but on something else in the environment.
But you can write any checkA e as checkB $ const e whereas a function like all_spaces = checkB (all . isSpace) is hard to write using checkA (suppose you are doing something like “map (checkB predicate)”) since checkA doesn't look at the second argument.
BTW, I also don't want to take too strong a position on the name ;-)
me neither, but check (all . isOK) reads nicely ;-) -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk http://www.chaos.org.uk/~jf/Stuff-I-dont-want.html (updated 2009-01-31)

On 22/08/2009 16:22, Jon Fairbairn wrote:
Duncan Coutts
writes: On Sat, 2009-08-22 at 10:18 +0200, Joachim Breitner wrote:
Hi,
I propose the attached change
Fri Aug 21 19:17:12 CEST 2009 Joachim Breitner
* Add justIf to Data.Maybe As Jón was suggesting we might want to generalise to MonadPlus rather than putting it in Data.Maybe, it becomes rather similar to the existing function 'guard':
[...] some alpha conversion
checkA :: MonadPlus m => Bool -> a -> m a checkA True x = return x checkA False _ = mzero
Using a Bool for the condition is a tad more general than a predicate like:
checkB :: MonadPlus m => (a -> Bool) -> a -> m a
I'd say the generality comparison goes the other way:
In particular, the use case in Cabal does not fit the predicate pattern because the condition is not a condition on the value being returned but on something else in the environment.
But you can write any
checkA e as checkB $ const e
Right, but checkB p x = checkA (p x) x. Also, checkA p = (guard p >>) . return
whereas a function like
all_spaces = checkB (all . isSpace)
I think that for consistency with if/then/else and guard we should use checkA. It's not that hard to write all_spaces xs = checkA (all (isSpace xs)) xs if that's really what you want. I wouldn't call checkB more "general"; to me it's just a minor convenience issue, which is outweighed by consistency and simplicity.
is hard to write using checkA (suppose you are doing something like “map (checkB predicate)”) since checkA doesn't look at the second argument.
the "applying check to a list" case is not hard either: zipWithM checkA (map p xs) xs again, if that's what you want to do. Cheers, Simon

On 2009-08-25 at 12:32BST Simon Marlow wrote:
I think that for consistency with if/then/else and guard we should use checkA.
See my response to Sebastian.
It's not that hard to write
all_spaces xs = checkA (all (isSpace xs)) xs
if that's really what you want.
Not /hard/, but it involves using xs twice, which should tell us something.
I wouldn't call checkB more "general"; to me it's just a minor convenience issue, which is outweighed by consistency and simplicity.
See response to Sebastian.
is hard to write using checkA (suppose you are doing something like “map (checkB predicate)”) since checkA doesn't look at the second argument.
the "applying check to a list" case is not hard either:
zipWithM checkA (map p xs) xs
which involves duplication again, and on top of that zipWithM, which while not /hard/ is hardly conceptually simple. Jón -- Jón Fairbairn Jon.Fairbairn at cl.cam.ac.uk

On Wed, 2009-08-26 at 18:58 +0100, Jon Fairbairn wrote:
It's not that hard to write
all_spaces xs = checkA (all (isSpace xs)) xs
if that's really what you want.
Not /hard/, but it involves using xs twice, which should tell us something.
I'm not sure it does tell us much, given that there are also cases where we need to use it only once, and would be forced to use \_ -> to ignore it in the predicate. The two forms are clearly inter-convertible and one form is more convenient in some situations while the other is more convenient in others. Duncan

Duncan Coutts
On Wed, 2009-08-26 at 18:58 +0100, Jon Fairbairn wrote:
It's not that hard to write
all_spaces xs = checkA (all (isSpace xs)) xs
if that's really what you want.
Not /hard/, but it involves using xs twice, which should tell us something.
I'm not sure it does tell us much,
One thing it tells us is that it's going to be awkward to write in a point-free style.
given that there are also cases where we need to use it only once, and would be forced to use \_ -> to ignore it in the predicate.
The other thing it tells us is that it makes a linear (or should I be saying single-threaded here?) term look like it's not. Using const in the opposite case doesn't have that effect. -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk http://www.chaos.org.uk/~jf/Stuff-I-dont-want.html (updated 2009-01-31)

Hi, Am Samstag, den 22.08.2009, 16:10 +0100 schrieb Duncan Coutts:
In this use case the result is typically a lot bigger than the condition, so the condition goes first rather than last.
At first I wrote justIf this way (justIf cond $ value), and then noticed the how nice "value `justIf` cond" sounds when read out aloud. I’m fine with either order, and your point about argument size is a valid one. Greetings, Joachim -- Joachim Breitner e-Mail: mail@joachim-breitner.de Homepage: http://www.joachim-breitner.de ICQ#: 74513189 Jabber-ID: nomeata@joachim-breitner.de

Hi, Inspired by a discussion we've been having around the network package and its API I would like to ask: Are all these small little functions really worth it? They're trivially defined using the current API and they make the current API bigger and hence more complicated. Is there a way to figure out which are the most general functions expose them and let developers use composition to define the rest? Just a thought, Johan

Johan Tibell wrote:
Are all these small little functions really worth it? They're trivially defined using the current API... let developers use composition to define the rest?
I completely agree with you. But in this case, even though these functions really are trivial, they come up *all* the time, and there is just something awkward about them. We certainly won't add more than one of the two: justIf x b = guard b >> return x check p x = guard (p x) >> return x justIf = flip $ check . const check = ap justIf Perhaps the following is a bit of an explanation of why they feel awkward: <yitz> @pl \ p x -> guard (p x) >> return x <lambdabot> (`ap` return) . (((>>) . guard) .) <yitz> @pl \ p x -> if p x then return x else mzero <lambdabot> flip flip mzero . (`ap` return) . (if' .) Please note that if we choose to add justIf, it should be spelled with an uppercase 'I' to be consistent with Haskell conventions. Thanks, Yitz

On Tue, Aug 25, 2009 at 1:11 PM, Yitzchak Gale
Johan Tibell wrote:
Are all these small little functions really worth it? They're trivially defined using the current API... let developers use composition to define the rest?
I completely agree with you. But in this case, even though these functions really are trivial, they come up *all* the time, and there is just something awkward about them.
We certainly won't add more than one of the two:
justIf x b = guard b >> return x check p x = guard (p x) >> return x
As you showed they are awkward to express in point-free style but as you demonstrated above they're trivially expressed using the monadic operators and guard. That several people want several different variation also suggests that the proposed version perhaps isn't useful enough to warrant inclusion in the library. Cheers, Johan

On Sat, 22 Aug 2009, Joachim Breitner wrote:
Hi,
I propose the attached change, with a discussion timeframe until end of September. The corresponding ticket is http://hackage.haskell.org/trac/ghc/ticket/3446
I proposed the same with reversed parameter order and the name 'toMaybe' years ago and it was rejected. http://www.haskell.org/pipermail/libraries/2004-July/002381.html However, I have added it to my own utility library. http://code.haskell.org/~thielema/utility/src/Data/Maybe/HT.hs
participants (8)
-
Brent Yorgey
-
Duncan Coutts
-
Henning Thielemann
-
Joachim Breitner
-
Johan Tibell
-
Jon Fairbairn
-
Simon Marlow
-
Yitzchak Gale