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

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

On 06/04/2012 09:25 PM, Henning Thielemann wrote:
> On Mon, 4 Jun 2012, Andreas Abel wrote:
>> 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.
> What is whenM_ ? Do you mean mapM_ ?


>> >> :: m () -> m b -> b
>> mapM_ :: (a -> m ()) -> [a] -> m ()
>> forM_ :: [a] -> (a -> m ()) -> m ()
>> sequence_ :: [m ()] -> m ()
>> forever :: m () -> m ()
>> and many more, like zipWithM_, foldM_, replicateM_.
> I would prefer these strict types, too.

Ok, well, then you probably would not want to use mapM_ and the like, 
but instead

   mapM (void . f) l

which instantiates the type b to (), giving above typings.

> Alternatively I have wondered in the past whether it might be a good
> idea to generalize them to:
>> mapM_ :: Monoid b => (a -> m b) -> [a] -> m b
>> forM_ :: Monoid b => [a] -> (a -> m b) -> m b
>> sequence_ :: Monoid b => [m b] -> m b
>> forever :: Monoid b => m b -> m b
> This would still propagate monadic result type () if the final monadic
> action has result type ().
> http://www.haskell.org/pipermail/haskell-cafe/2009-January/054243.html

But that would not be backwards compatible.

>> 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.
> Since the addition of 'void' the noise has become acceptable for me.
> I would follow a kind of "separation of concerns". Ignoring results is
> one step and performing forM_, when etc. is the second step.

Ok.  But I am really surprised that an operation should not get the 
maximally sensible type.

It seems that I like to think of () as a terminal type (in the sense of 
category theory), but this intuition is not shared by everyone.  [I am 
aware that () is NOT the terminal type in Haskell.]

>> 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.
> Last time I asked the question, what application you do have in mind. Is
> your code cluttered with void's or do you just need it occasionally?

The application is that I have a function that provides a resource that 
may be present or not.  If it is not present, an exception is thrown 
(that is the monadic effect).  If I am just interested in checking the 
presence of the resource, I can call this function in a do-block.  But I 
am not allowed to call it in a 'when', without 'void'ing it.  That is 

To reconcile the 'strict' vs. 'liberal' programmers, it seems that 
library functions need to have different types depending on whether


is set or not...


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