I have a function
parseArgs :: [String] -> StdGen -> IO ()
which selects the function to run. The main looks like
main = parseArgs <$> getArgs <*> getStdGen >>= id
The problem I have, parseArgs <$> getArgs <*> getStdGen
is of type IO (IO ())
, which I extract using (>>= id)
which is of type Monad m => m (m b) -> m b
. Is there a way to avoid requiring the "extraction" of the value while having just a single line function?
The easiest way would be with join
:
main = join $ parseArgs <$> getArgs <*> getStdGen
Personally, I would prefer the form
main = join $ liftM2 parseArgs getArgs getStdGen
where
join :: Monad m => m (m a) -> m a
liftM2 :: Monad m => (a -> b -> r) -> m a -> m b -> m r
Or just use a do
main = do
args <- getArgs
gen <- getStdGen
parseArgs args gen
You can define an operator for this:
infixl 4 <&>
(<&>) :: Monad m => m (a -> m b) -> m a -> m b
f <&> x = f >>= (x >>=)
If you have a function of type
f :: Monad m => (a1 -> a2 -> ... -> an -> m b) -> m a1 -> m a2 -> ... -> m an -> m b
then you can write
fx :: Monad m => m b
fx = f <$> x1 <*> x2 <*> ... <&> xn
where each xi
has type m ai
.
In your case it would be simply
parseArgs <$> getArgs <&> getStdGen
You could pair up the arguments and put them through a single bind:
main = uncurry parseArgs =<< (,) <$> getArgs <*> getStdGen
This avoids the extraction from nested IO. Admittedly it's no shorter but I find it easier to think about.
It fits a general pattern of doTheWork =<< getAllTheInputs
which might be the way you'd end up arranging things anyway, if the code was more complicated.