An alternative to Control.Final is a using the writer monad.
instance Monoid a => Monoid (IO a) where mempty = return mempty mappend = liftA2 mappend stmExampleW = do tv <- newTVarIO "xxx" join $ atomically $ execWriterT $ do val <- lift $ readTVar tv case val of "xxx" -> do lift $ writeTVar tv "foobar" tell $ print "it was xxx" "yyy" -> do lift $ writeTVar tv "quux" tell $ print "it was yyy" tell $ print "I finished"
This works. Unfortunately when using the writer, you have to
every operation of the base monad and also there is no such thing
finalTell to specify that this is a return point of the
function. On the positive side, the writer alternative let's you
IO operations together using a
final can't do that.