## How to terminate a computation that runs in the `IO` monad?

Question

There is a library that provides a data type `F`

and a function of type

```
ffoldlIO :: (b -> a -> IO b) -> b -> F a -> IO b
```

The function is similar to

```
foldlIO :: (b -> a -> IO b) -> b -> [a] -> IO b
foldlIO f a = \xs -> foldr (\x r (!a') -> f a' x >>= r) return xs a
```

I wonder whether `foldlIO`

(and thus `ffoldlIO`

) can run in a short-circuit fashion.

Consider this example:

```
example1 :: IO Int
example1 = foldlIO (\a x -> if a < 4 then return (a + x) else return a) 0 [1..5]
```

Here `foldlIO`

traverses the entire list, but what if we throw an exception to stop the computation and then catch it? Something like this:

```
data Terminate = Terminate
deriving (Show)
instance Exception Terminate
example2 :: IO Int
example2 = do
ra <- newIORef 0
let step a x
| a' < 4 = return a'
| otherwise = writeIORef ra a' >> throwIO Terminate
where a' = a + x
foldlIO step 0 [1..] `catch` \(_ :: Terminate) -> readIORef ra
```

Is this reliable? Is there a better way to terminate a computation that runs in the `IO`

monad (and no other monad) or am I not supposed to do this at all?

Show source

## Answers ( 2 )

For example, you can use

`ContT`

monad transformer like this:Also, you can define you own version of

`foldM`

with posibility of termination.But this way (with

`ContT`

) has one problem. You can't easy do some`IO`

actions. For example, this code will not be compiled, because`step`

function must return value of type`ContT Int IO Int`

not`IO Int`

.Fortunately, you can solve this by the

`lift`

function, like this:My first answer was not correct. So, I'll try to improve.

I think that the use of exceptions to terminate in IO monad is not a hack but it does not look clean. I propose to define the instance

`MonadCont IO`

like this:Then you can rewrite your example more cleaner.

Variant with

`IOREf`

.