[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_ ?

Probably...

>> >> :: 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 
counterintuitive.

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

   -fwarn-unused-do-bind

is set or not...

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/



More information about the Libraries mailing list