I have two functions, one that tries to get a token from a webservice and may fail, and one that tries to use this token to get the username and may fail.
getToken :: IO (Maybe Token)
getUsername :: Token -> IO (Maybe String)
I would like to take the result of getToken and feed it to getUsername. If there was only IO or Maybe, I could simply use bind, but since there are down nested monads, I can't. How can I write something equivalent to getToken >>= getUsername :: IO (Maybe String) ?
More generally, what function has type m1 m2 a -> (a -> m1 m2 b) -> m1 m2 b?
Bonus question: how would I do that using the do notation in an IO context?
I have defined a function useToken showing your use case:
type Token = String
getToken :: IO (Maybe Token)
getToken = undefined
getUsername :: Token -> IO (Maybe String)
getUsername = undefined
useToken :: IO (Maybe String)
useToken = do
  token <- getToken
  case token of
    Just x -> getUsername x
    Nothing -> return Nothing
If you don't want to use do notation, then you can use:
useToken2 :: IO (Maybe String)
useToken2 = getToken >>= \token -> maybe (return Nothing) getUsername token
Or using monad transformers, your code will become simpler:
import Control.Monad.Trans.Maybe
type Token = String
getToken :: MaybeT IO Token
getToken = undefined
getUsername :: Token -> MaybeT IO String
getUsername = undefined
useToken :: MaybeT IO String 
useToken = do
  token <- getToken
  getUsername token
Note that, you can also directly lift IO operations inside the monad transformer. As @Robedino points out, now the code will be more concise without do notation:
useToken :: MaybeT IO String 
useToken = getToken >>= getUsername
                        As people in the comments suggest, you should just use monad transformers.
However you can avoid this in your case. Monads do not commute in general, so you can't write a function with this signature
bind' :: (Monad m, Monad n) => m (n a) -> (a -> m (n b)) -> m (n b)
But all is ok, if the inner monad is an instance of the Traversable class:
import Data.Traversable as T
import Control.Monad
joinT :: (Monad m, Traversable t, Monad t) => m (t (m (t a))) -> m (t a)
joinT = (>>= liftM join . T.sequence)
liftMM :: (Monad m, Monad n) => (a -> b) -> m (n a) -> m (n b)
liftMM = liftM . liftM
bindT :: (Monad m, Traversable t, Monad t) => m (t a) -> (a -> m (t b)) -> m (t b)
bindT x f = joinT (liftMM f x)
and the Maybe monad is; hence
type Token = String
getToken :: IO (Maybe Token)
getToken = undefined
getUsername :: Token -> IO (Maybe String)
getUsername = undefined
useToken :: IO (Maybe String)
useToken = getToken `bindT` getUsername
Also, with the {-# LANGUAGE RebindableSyntax #-} you can write
(>>=) = bindT
useToken :: IO (Maybe String)
useToken = do
    x <- getToken
    getUsername x
Update
With the type-level compose
newtype (f :. g) a = Nested { runNested :: f (g a) }
you can define a monad instance for nested monads:
instance (Monad m, Traversable t, Monad t) => Monad (m :. t) where
    return  = Nested . return . return
    x >>= f = Nested $ runNested x `bindT` (runNested . f)
Your example then is
type Token = String
getToken :: IO (Maybe Token)
getToken = undefined
getUsername :: Token -> IO (Maybe String)
getUsername = undefined
useToken :: IO (Maybe String)
useToken = runNested $ Nested getToken >>= Nested . getUsername
Or like you would do with the MaybeT transformer:
type Nested = (:.)
type Token = String
getToken :: Nested IO Maybe Token
getToken = undefined
getUsername :: Token -> Nested IO Maybe String
getUsername = undefined
useToken :: Nested IO Maybe String
useToken = getToken >>= getUsername
runUseToken :: IO (Maybe String)
runUseToken = runNested useToken
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With