Search code examples
haskellio-monad

Compose IO Operations


I am trying to compose some IO wrapped functions.

My current code (that works) is:

getUserHome :: IO String
getUserHome = do
    usr_id <- getRealUserID
    homeDirectory <$> getUserEntryForID usr_id

What I am looking for is a more convenient notation (one without using the do-keyword).

Without any of the Monadic salad I would just write

getUserHome = homeDirectory . getUserEntryForID . getRealUserID

I would guess there is an alternative operator for the . that respects the Monad ..? But in all my searching, I have not found it.


I tried <$> but that does not seem to be what i want:

src/Main.hs:49:21: error:
    • Couldn't match type ‘IO UserEntry’ with ‘UserEntry’
      Expected type: UserID -> UserEntry
        Actual type: UserID -> IO UserEntry
    • In the second argument of ‘(<$>)’, namely ‘getUserEntryForID’
      In the first argument of ‘(<$>)’, namely
        ‘homeDirectory <$> getUserEntryForID’
      In the expression:
        homeDirectory <$> getUserEntryForID <$> getRealUserID
   |
49 |   homeDirectory <$> getUserEntryForID  <$> getRealUserID -- usr_id

Solution

  • You can use >>=, since Haskell eventually "desugars" the do block to this:

    getUserHome :: IO String
    getUserHome = getRealUserID >>= \usr_id -> homeDirectory <$> getUserEntryForID usr_id
    

    this can be simplified with:

    getUserHome :: IO String
    getUserHome  = getRealUserID >>= fmap homeDirectory . getUserEntryForID
    

    or:

    getUserHome :: IO String
    getUserHome  = getRealUserID >>= (homeDirectory <$>) . getUserEntryForID