
On Tue, 5 Jun 2012, Andreas Abel wrote:
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
This would result in 'm [()]' not in 'm ()'. I could e.g. get information from the number elements in the [()] list, but () tells me nothing. Thus they are really different.
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.
Not completely. You may need additional type annotations.
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.
There are other functions, like 'asTypeOf' that have intentionally not the most general type. :-) My concern is safety and safety means to intentionally forbid things. That's why I prefer Haskell to C or MatLab. E.g. C by default ignores results from functions if they are not used. But this way, people may write (a==b;) instead of (a=b;) without noticing the mistake.
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.
How do you free the resource if you ignore the returned handle? If checking for an exception this way is a common pattern in your code, how about writing a function that catches the exception and run some code, if there is no exception? It might have a signature like whenAvailable :: IO resource -> IO () -> IO () and might be used like this whenAvailable getResource $ do thingsToDoWhenResourceIsAvailable
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...
Something like a type system that does not only support 'correct' and 'wrong', but also 'suspect', would solve the problem. :-)