[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
landPlane
(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
-fwarn-unused-do-bind
that prevents you from ignoring results silently, in this case you would
have to write
do _ <- gearDown
landPlane
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...
Cheers,
Andreas
> * 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
http://www2.tcs.ifi.lmu.de/~abel/
More information about the Libraries
mailing list