Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9251665
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 18, 20262026-06-18T10:45:34+00:00 2026-06-18T10:45:34+00:00

I have the following implementation of a concurrent thread manager newtype Query = Query

  • 0

I have the following implementation of a concurrent thread manager

newtype Query = Query String

type ThreadWorker = (Query, ThreadStatus)
data ThreadStatus = Running | Finished | Threw IOException

newtype ThreadManager = Manager (MVar (M.Map ThreadId (MVar ThreadWorker)

I want to write manageWorkers :: ThreadManager -> IO () that traverses the Map and looks at the ThreadStatus of the ThreadWorker.

If the ThreadWorker is finished, then it is deleted from the ThreadManager. If an exception has been thrown, then it should be handled (print to stdout is fine for example purposes) and a new thread should be forked to process the query (assume the existance of a function runQuery :: Query -> IO a) and be added to the ThreadManager, else the thread is still running and should be left alone.

my first attempt at an implementation was:

manageWorkers :: ThreadManager -> IO ()
manageWorkers (Manager mgr) =
    modifyMVar mgr $ \m -> do
        m' <- M.traverseWithKey manageWorker m
        return (m', ())
where manageWorker :: ThreadId -> MVar ThreadWorker -> IO (MVar ThreadWorker)
      manageWorker tid wkr = tryTakeMVar wkr >>= \mwkr ->
          case mwkr of
               Just (_, Finished) -> undefined -- need to delete this finished ThreadWorker
               Just (q, Threw e ) -> do
                   putStrLn ("[ERROR] " ++ show e)
                   tid' <- forkIO $ runQuery q
                   undefined -- need to add new ThreadWorker
               Just r -> newMVar r
               _ -> newEmptyMVar

but then I got stuck, it doesnt seem possible to delete or add from/to the ThreadManager while in manageWorker. I’m not sure if it’s possible to do what I want from a traverse-like function.

Is it possible to implement this manageWorkers function using my ThreadManager or is there a better abstraction out there?

EDIT: at ThomasM.DuBuisson’s suggestion to use a fold, I now have the following

manageWorkers (Manager mgr) =
    modifyMVar mgr $ \m ->
    return (M.foldrWithKey manageWorker M.empty m, ())
where manageWorker :: ThreadId -> MVar ThreadWorker -> M.Map ThreadId (MVar ThreadWorker)
                      -> IO (M.Map ThreadId (MVar ThreadWorker))
      manageWorker tid wkr ts = tryTakeMVar wkr >>= \mwkr ->
          case mwkr of
              Just (q, Threw e) -> do
                  putStrLn ("[ERROR] " ++ show e)
                  wkr' <- newEmptyMVar
                  tid' <- forkIO $ runQuery q
                  return $ M.insert tid' wkr' ts
              Just (_, Running) -> return $ M.insert tid wkr
              _ -> return ts

the only problem is that obviously manageWorker‘s signature does not work with M.foldrWithKey. I need a M.foldrWithKeyM :: Monad m => (k -> a -> b -> m b) -> b -> M.Map k a -> m b but such a thing does not exist, and I’m having trouble composing it myself.

Obviously I can use unsafePerformIO to escape the IO monad and satisfy the compiler, but I would only use that as a last resort. Is this a situation in which it makes sense to use unsafePerformIO?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-18T10:45:35+00:00Added an answer on June 18, 2026 at 10:45 am

    In my opinion, you question is irrelevant to concurrency.
    You just want to traverse a map, meanwhile, delete some keys from the map or insert some keys in the map and perform some IO actions.
    The problem is traverseWithKey cannot delete keys from the map or insert keys in the map, foldrWithKey cannot perform IO actions.
    You need a M.foldrWithKeyM :: Monad m => (k -> a -> b -> m b) -> b -> M.Map k a -> m b
    Indeed, such a thing does not exist. But if you look at the documentation of foldrWithKey, which states:

    foldrWithKey f z == foldr (uncurry f) z . toAscList. 
    

    We can guess such M.foldrWithKeyM can be composed if we replcae foldr by foldM.

    The following is my solution.

    manageWorkers :: ThreadManager -> IO ()
    manageWorkers (Manager mgr) = 
        modifyMVar mgr $ \m -> do
            m' <- foldM manageWorker m (M.toList m)
            return (m', ())
      where manageWorker :: M.Map ThreadId (MVar ThreadWorker) -> (ThreadId, MVar ThreadWorker) -> IO (M.Map ThreadId (MVar ThreadWorker))
            manageWorker ts (tid, wkr) = tryTakeMVar wkr >>= \mwkr ->
                case mwkr of
                     Just (_, Finished) -> return $ M.delete tid ts -- need to delete this finished ThreadWorker
                     Just (q, Threw e ) -> do
                           putStrLn ("[ERROR] " ++ show e)
                           wkr' <- newEmptyMVar
                           tid' <- forkIO $ runQuery q
                           return $ M.insert tid' wkr' ts -- need to add new ThreadWorker
                     _ -> return ts
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

have the following implementation $.ajax({ type: POST, url: /Member/SaveMember, data: $('form').serialize(), success: refreshGrid() how
I have the following: @implementation DataSource + (NSArray *)someData { static NSArray *data =
I have following implementation public abstract class BaseAcion extends ActionSupport { private String result;
I have this following codes: @implementation MyImageView @synthesize image; //image is a UIImage -
I have the following code implementation of my generic singleton provider: public sealed class
I have the following own Interface Implementation in my Fragment: @Override public void onReportChanged(Fragment
I have the following scenario.The implementation is required for a real time application. 1)I
I have a problem with the following implementation of hook_cron in Drupal 6.1.3. The
Given I have two File objects I can think of the following implementation: public
I have the following classes/protocols: @interface Super @end @implementation Super @end @interface Sub1 @end

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.