One idea: Combine the timeout (suggested by @MathematicsOrchid) with mutable variables from SafeSemaphore to store intermediate values โโeach time your process calculates a partial result:
import Control.Monad import Control.Concurrent.MSampleVar import System.Timeout fac :: Integer -> Integer fac 0 = 1 fac n = n * fac (n - 1) tmo :: Int -> ((a -> IO ()) -> IO ()) -> IO (Maybe a) tmo ms f = do mvar <- newSV Nothing timeout ms (f (writeSV mvar . (Just $!))) readSV mvar longComp :: (Integer -> IO ()) -> IO () longComp save = let loop n = save (fac n) >> loop (n + 1) in loop 0 main :: IO () main = tmo 10000 longComp >>= print
The function passed to tmo receives an IO action as the first argument, which can be used to save intermediate results. If it receives a timeout, the last stored result is returned. The result is converted to WHNF, so the actual calculation takes place in a thread that stores the result, and not in the one that processes it when it returned from tmo .
In this option, the function passed to tmo should retain its output; it cannot return it. But it would be easy to change it so that its signature is (a -> IO ()) -> IO a .
If you want to keep it clean, I would suggest creating your own monad that encapsulates this idea without letting go of IO .
Update: Please Note:
There is no guarantee that the exception will be delivered quickly, although runtime will strive to ensure that no arbitrary delays occur. In the GHC, an exception can only be raised when the thread reaches a safe point, where is a safe point, where is the memory allocation. Some loops do not perform any memory allocation inside the loop and therefore cannot be interrupted by throwTo.
(from throwTo documentation). In the above example, fac does not allocate any memory, so it will not be interrupted immediately for large numbers.
Update:. I created a small library based on those ideas that define monads for computations that can return partial results before returning the final one or dying at a timeout. See https://github.com/ppetr/timeout-with-results
Petr pudlรกk
source share