以下のコードの目的は、子スレッドのエラーがメインスレッドに影響しないようにしたいため、隔離しているようです。
actionIO :: IO a -> IO a
actionIO action = do
mv <- newEmptyMVar :: IO (MVar (Either SomeException a))
_tid <- forkIO $ do
result <- try acttion
putMVar mv result
result <- takeMVar mv
case result of
Left e -> throwIO e
Right r -> return
actionIO action = do
mv <- newEmptyMVar :: IO (MVar (Either SomeException a))
_tid <- forkIO $ do
result <- try acttion
putMVar mv result
result <- takeMVar mv
case result of
Left e -> throwIO e
Right r -> return
1. actionIO :: IO a -> IO a
IO aのアクションを引数にとり、結果もIO aとして返す関数です。引数のactionを別スレッドで実行し、その結果を取得します。
2. mv <- newEmptyMVar :: IO (MVar (Either SomeException a))
新しい空のMVarを作成します。MVarはスレッド間で値のやり取りができる同期変数です。
型は MVar (Either SomeException a) としています。Either SomeException aは、「例外が起きたか」あるいは「正常に値が得られたか」を表すために使います。
3. _tid <- forkIO $ do ...
forkIOで新しい軽量スレッドを作り、その中でactionを実行します。
forkIOはスレッドIDを返しますが、このコードでは使わないので_tidとして無視しています。
4. result <- try action
tryは、例外が発生する可能性があるIOアクションを安全に実行し、成功時はRight a 例外発生時はLeft SomeExceptionの形で結果を返します。
5. putMVar mv result
mv(空のMVar)に結果を格納します。これでメインスレッドはこの結果を待つことができます。
6. result <- takeMVar mv
メインスレッドで、mvに格納されるまで待ちます。forkIOの中の処理が終わりputMVarが呼ばれるまでブロックされます。