[Haskell] Types of when and unless in Control.Monad

Andreas Abel andreas.abel at ifi.lmu.de
Mon Jun 4 20:35:58 CEST 2012

On 04/22/2012 01:49 PM, Ivan Lazar Miljenovic wrote:
> On 22 April 2012 21:39, Christian Höner zu Siederdissen
> <choener at tbi.univie.ac.at>  wrote:
>> * Julian Gilbey<julian at d-and-j.net>  [22.04.2012 09:22]:
>>> On Sat, Apr 21, 2012 at 08:28:27PM -0500, Strake wrote:
>>>> On 21/04/2012, Andreas Abel<andreas.abel at ifi.lmu.de>  wrote:
>>>>> to avoid silly "return ()" statements like in
>>>>>     when cond $ do
>>>>>       monadicComputationWhoseResultIWantToDiscard
>>>>>       return ()
>>>> (when cond ∘ void) monadicComputationWhoseResultIWantToDiscard
>>>> or
>>>> when cond $ ()<$ monadicComputationWhoseResultIWantToDiscard
>>> How is that simpler than
>>>    when cond monadicComputationWhoseResultIWantToDiscard
>>> which it would be with the suggested new type?
>>>     Julian
>> Wouldn't "when_" and "unless_" or similar be better? I'd probably like
>> to have the compiler annoy me, since it is not clear that I want to
>> discard the result. If I really want to discard, I should have to make
>> it clear as there is probably a good reason for the inner function to
>> return a result in the first place?
> Agreed; I'm not sure if I agree with having such functionality
> (Henning makes some good points), but if people deem it desirable then
> I think it would be better to have them with new names for the reasons
> you state.

Mmh, this discussion has cooled down, but I just found your answers 
which had been stashed away by my mail agent, and I feel I have to reply...

Concerning the suggestion that when_ would be in sync with forM_ and 
whenM_ I'd say: not really.  forM_ and whenM_ discard the result of the 
monadic computation, while when and when_ do not even have such a 
result.  They always just perform some monadic effect and return nothing.

Repeating myself, 'when' can never have a result, since it is an if-then 
without an else.  Thus, it is a proper command; and if you want to have 
a conditional monadic computation which does return a result, you can 
simply not use 'when' or 'unless', logic forces you to use 'if' or 'ifM'.

I do not understand the worries that one could accidentially use 'when' 
with a monadic computation whose result one actually cares for.  If that 
was the intention of the library designers, they should have given many 
other function a more specific type, most prominently

   >> :: m () -> m b -> b

That would have ensured that you cannot discard the result of the first 
computation by accident.  But would you want to work with this?  My 
answer is no.

Other types that would be changed to implement this kind of safety 
policy are:

   mapM_ :: (a -> m ()) -> [a] -> m ()
   forM_ :: [a] -> (a -> m ()) -> m ()
   sequence_ :: [m ()] -> m ()
   forever :: m () -> m ()

and many more, like zipWithM_, foldM_, replicateM_.

Sorry, but I think all these function have been given their maximal 
general type

   ==> to be able to ignore a result of a monadic computation

   ==> without further noise.

In my opinion, the types of when and unless are not general enough, an 
that is, imho, just an accident of history.  Because it is the type that 
inferred for the shortest definition, which is

   when cond m = if cond then m else return ()

Please reevaluate my proposal to change to

   when   :: Bool -> m a -> m ()
   unless :: Bool -> m a -> m ()

in the light of the above arguments.


Andreas Abel  <><      Du bist der geliebte Mensch.

Theoretical Computer Science, University of Munich
Oettingenstr. 67, D-80538 Munich, GERMANY

andreas.abel at ifi.lmu.de

More information about the Libraries mailing list