I have the following that works similar to forkIO
, but returns a blocking "channel" that lets you receive the result of a forked IO computation. My main concern is its handling of exceptions. It will return Nothing
if something is raised, but can't supply any more information then that.
I tried using try
inside of wrapAction
, which returns an (Either Exception a)
, but I couldn't figure out what exception type to use. I tried SomeException
thinking it would catch everything, and supply a message, but it doesn't. Running a computation that divides by 0 resulted in Right
being returned, but threw a "divide by 0" exception when I tried inspecting the result. Surely in a generic situation like this I can't specifically catch every possible exception (given a user could create their own). How should I set up the exception handling so that a Left
can be returned with an exception message?
import Control.Concurrent
import Control.Exception
data RThread a = RThread (IO a) (MVar (Maybe a))
newReturn :: IO a -> IO (RThread a)
newReturn act = newEmptyMVar >>= return . RThread act
wrapAction :: RThread a -> IO ()
wrapAction (RThread act chan) = onException (act >>= putMVar chan . Just) (putMVar chan Nothing)
returnFork :: IO a -> IO (RThread a)
returnFork act = do
nR <- newReturn act
forkIO $ wrapAction nR
return nR
waitForResult :: RThread a -> IO (Maybe a)
waitForResult (RThread _ chan) = takeMVar chan
Any critique would be appreciated
Simple usage:
import System.Random
import Control.Monad
testFn :: IO [Int]
testFn = returnFork (replicateM 100 $ randomRIO (1,100) >>=
waitForResult
Although realistically you would pass the result of waitForResult
somewhere else to wait.