Interrupting Long Net Computing in MonadState

I cannot figure out the correct way to interrupt a long clean calculation with a SIGINT signal.

In the simple example below, I have a slowFib function that simulates a lengthy calculation. When it only runs in IO monad, I can terminate it with Cc (using async for the spawning worker).

However, when I push the calculation MonadState, MonadIO stack MonadState, MonadIO , it no longer works ... On the other hand, a simple threadDelay in the same stack can be completed.

The following code:

 {-# LANGUAGE FlexibleContexts #-} module Main where import Data.Monoid import Control.DeepSeq import Control.Concurrent import Control.Concurrent.Async import Control.Monad.State -- import Control.Monad.State.Strict import System.Posix.Signals slowFib :: Integer -> Integer slowFib 0 = 0 slowFib 1 = 1 slowFib n = slowFib (n - 2 ) + slowFib (n - 1) data St = St { x :: Integer } deriving (Show) stateFib :: (MonadState St m, MonadIO m) => Integer -> m Integer stateFib n = do let f = slowFib n modify $ \st -> st{x=f} return f stateWait :: (MonadState St m, MonadIO m) => Integer -> m Integer stateWait n = do liftIO $ threadDelay 5000000 return 41 interruptable n act = do putStrLn $ "STARTING EVALUATION: " <> n e <- async act installHandler sigINT (Catch (cancel e)) Nothing putStrLn "WAITING FOR RESULT" waitCatch e main = do let s0 = St 0 r <- interruptable "slowFib" $ do let f = slowFib 41 f `deepseq` return () return f r <- interruptable "threadDelay in StateT" $ runStateT (stateWait 41) s0 putStrLn $ show r r <- interruptable "slowFib in StateT" $ runStateT (stateFib 41) s0 putStrLn $ show r 

I suspected this was due to a lazy assessment. I already realized that in the first example (using only the IO monad) I have to force the result. Otherwise, evaluating async just returns thunk.

However, all my attempts to do something similar in MonadState failed. In any case, this seems more complicated, since the asynchronous thread does not return immediately. It waits until the result is calculated. For some reason, I just can't stop it when a pure calculation "blocks".

Any clues?

PS. In my case, there are too many features to interrupt computations in the Jupyter user kernel using the jupyter package. Functions that evaluate user input are found exactly in MonadState and MonadIO .

+5
source share
1 answer

The calculation is apparently locked on putStrLn $ show r , i.e. outside the interruptable function. Note that stateFib does not produce a result, so async exits almost immediately. All work is delayed until putStrLn tries to print the result. Try to force the calculation earlier:

 stateFib :: (MonadState St m, MonadIO m) => Integer -> m Integer stateFib n = do let f = slowFib n modify $ \st -> st{x=f} f `seq` return f 
+2
source

Source: https://habr.com/ru/post/1272623/


All Articles