[Haskell-cafe] best practice for lifting of IO and could lifting be automated?

Dimitri DeFigueiredo defigueiredo at ucdavis.edu
Fri Oct 23 19:39:32 UTC 2015

Hello All,

I have recently encountered 2 situations where I needed an IO action, 
but only had a monad stack with IO at the bottom.

The two examples were:

1. from Control.Concurrent.Async
    withAsync :: IO a -> (Async a -> IO b) -> IO b

2. from Network.WebSockets
    runClient :: String       -- ^ Host
              -> Int          -- ^ Port
              -> String       -- ^ Path
              -> (Connection -> IO a) -- ^ Client application
              -> IO a

I need to pass a function that returns an IO action to both these functions.
I think my life would be easier if the function signatures were:

1. withAsync :: MonadIO mIO => mIO a -> (Async a -> mIO b) -> mIO b

2. from Network.WebSockets
    runClient :: MonadIO mIO =>
              -> String       -- ^ Host
              -> Int          -- ^ Port
              -> String       -- ^ Path
              -> (Connection -> mIO a) -- ^ Client application
              -> mIO a

There are many other examples, a notable one are the functions in 
Control.Exception also always expect an IO action.
I know we have libraries to solve this problem, such as lifted-async, 
lifted-base and the functionality in Control.Monad.Trans.Control.
But what are the best practices for writing code that uses Monadic 
actions? Should I always generalize my type signatures or just expect 
others to use the libraries when they need to?

Also, to some extent it seems trivial to re-write a library like async 
with the generalized signatures I need. I would just need to apply 
'lift' everywhere. Couldn't the compiler do this for me? ;-)



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20151023/1dcea57d/attachment.html>

More information about the Haskell-Cafe mailing list