Reputation: 10742
The type of (>>=)
is
(>>=) :: Monad m => m a -> (a -> m b) -> m b
I want a function that has the type:
(Monad m, Monad n) => m a -> (a -> n b) -> n b
This function could be used to chain different monads together.
I faced this problem when I was trying to get 3000
from the command-line arguments -p 3000
:
main = getArgs >>= (\args -> (elemIndex "-p" args) >>= (\id -> warpDebug (fromIntegral.read (args !! (id+1))) Ilm))
This clearly won't compile because getArgs
returns an IO [String]
and elemIndex
returns a Maybe Int
. A function of the above type could be used to elegantly solve this problem. My question is:
Upvotes: 9
Views: 376
Reputation: 13677
The answer depends on whether you need to use Maybe and IO monads together or separately.
If you need to use them together - the answer is that you need to compose IO
and Maybe
monads by constructing a stack of monad transformers containing IO monad and MaybeT monad transformer.
If you need them separately, then a simpler solution works:
import System.Environment
import Data.List
main = getArgs >>= (\args -> return (elemIndex "-p" args
>>= \y -> return $ y + 900) >>= print)
Note the return
. So you have Maybe
monad in the inner parentneses (between elemIndex
and 900
), but not IO. That is, you cannot perform IO actions before leaving Maybe
monad, as I showed with print.
Upvotes: 2
Reputation: 68172
This function doesn't exist because it would not make sense for all monads. It is basically equivalent to a monad unpacking function Monad m => m a -> a
--the only difference is that you immediately put it into another monad.
The reason this function is not defined for all monads is because it does not make sense for some of them. For example, take Maybe
: the only way to unpack it would be to throw an error if you have Nothing
, and runtime errors are looked down upon. A more extreme example would be IO
--using a function that could "unpack" IO
values would lead to weird and potentially nondeterministic behavior.
Thus, you do not have such a function in general. However, a lot of specific monads do come with such functions. A great example is runST
; this is actually a safe way for dealing with state. You actually do have such functions for both Maybe
and IO
(fromJust
and unsafePerformIO
respectively), but they have the problems I outlined above and you should avoid them.
The solution to your problem, then, is to see if there exists such a function for whichever monads you're dealing with. If there does, check any potential pitfalls--does it generate runtime errors or cause weird behavior?
In your case, if you are absolutely sure that the Maybe
is never Nothing
, use fromJust
. However, this is not generally good practice, so you should just stick to pattern matching the value out of the Maybe
.
Upvotes: 6
Reputation: 4072
Such a function doesn't exist. In fact, if you take n
to be the identity monad, it would allow you to construct a function m a -> a
, which clearly cannot be defined for all monads.
To address the general problem of "composing" two monads, you can look into monad transformers.
However, it seems overkill to use monad transformers in your example. You can simply define a function [String] -> Maybe Args
(for some custom type Args
- say Int
in the example) which does the command line argument processing, then pattern match on the result (or use maybe
) from within the IO
monad.
Upvotes: 21