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

Andreas Abel andreas.abel at ifi.lmu.de
Tue Jun 5 14:37:10 CEST 2012

On 06/04/2012 08:47 PM, Christian Höner zu Siederdissen wrote:
> Hi Andreas,
> I think you missed our point. Say:
> gearDown :: IO Bool
> landPlane :: IO ()
> do
>    g<- gearDown
>    if g
>    then landPlane
>    else error "we're all gonna die, bail out"
> But now, I am really lazy (in a bad way)
> do
>    when gearDown
>    landPlane

You probably meant to write

   do gearDown

(Since 'when' expects a pure Bool, the code you wrote does not 
type-check.)  Well, you can ignore results in a 'do', but this has 
nothing to do with 'when'.  There is a ghc flag


that prevents you from ignoring results silently, in this case you would 
have to write

   do _ <- gearDown

to make it obvious that you ignore a result of a monadic computation. 
Maybe you prefer this style, but I would like the freedom to silently 
ignore unneeded results.

> I can not now accidentally land my plane if my gear ist stuck in "up"
> (returned false). If "when" suppresses the return value, the compiler
> does not warn you if you use "when" together with a function that
> returns something important.

It seems you have confused condition- and then-part of 'when'.

> My point is /not/ that I want the result of "when", but that I want to
> know that I am currently suppressing the result of the inner action,
> which could be disastrous.
> And simply adding "when_" is the safest (one of the safer?) way of
> dealing with your wish.

The reason to have a mapM_ additionally to mapM is that in some cases, 
e.g. as last statement of a do block of type m (), mapM does not type check.

However, generalizing the type of 'when' does not break any programs, 
and then a when_ is superfluous.

More in an answer to Henning...


> * Andreas Abel<andreas.abel at ifi.lmu.de>  [04.06.2012 20:36]:
>> 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.
>> Cheers,
>> Andreas
>> --
>> 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
>> http://www2.tcs.ifi.lmu.de/~abel/

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