4

I'd like to use finally, signature IO a -> IO b -> IO a.

However, the operations I wanna use are based on a different monad than IO (namely Servant's ClientM).

I knew liftIO, but that seems to do the opposite -- IO a -> m a.

How can I transform my monads into IOs, or lift finally such as to operate on my monads instead?

Kiara Grouwstra
  • 5,723
  • 4
  • 21
  • 36

2 Answers2

9

Note that ClientM also has a MonadBaseControl IO ClientM instance which is for this sort of thing. For instance, I think the following should typecheck (and can be used with m ~ ClientM).

finally' :: MonadBaseControl IO m => m a -> m b -> m a
finally' x y = control $ \runInIO -> catch (runInIO x) (runInIO y)

EDIT

Not only does the above typecheck, but it is defined in lifted-base as finally.

Alec
  • 31,829
  • 7
  • 67
  • 114
  • 1
    Thanks for your help! I'd have gotten lost trying to find this black magic. I've somehow run into an error actually trying to use its `MonadBaseControl` instance though -- I've posted that as a new question [here](https://stackoverflow.com/questions/50439760/no-instance-for-trait-thats-already-implemented). – Kiara Grouwstra May 20 '18 at 21:58
1

It seems that ClientM must be run at some point with runClientM, which brings it down to IO.

Perhaps the simplest solution—if it happens to fit your case—would be to use finally to wrap that resulting IO action.

danidiaz
  • 26,936
  • 4
  • 45
  • 95