import Control.Concurrent import Control.Concurrent.STM threadA :: TChan Int -> TChan Int -> TChan () -> IO () threadA chan1 chan2 done = do ans <- atomically $ do writeTChan chan1 42 readTChan chan2 putStrLn $ "A: got answer " ++ show ans threadB :: TChan Int -> TChan Int -> TChan () -> IO () threadB chan1 chan2 done = do (query, answer) <- atomically $ do q <- readTChan chan1 let ans = 2 * q writeTChan chan2 ans return (q, ans) putStrLn $ "b: got query " ++ show query ++ ", answered " ++ show answer main :: IO () main = do chan1 <- newTChanIO chan2 <- newTChanIO done <- newTChanIO _ <- forkIO $ threadA chan1 chan2 done _ <- forkIO $ threadB chan1 chan2 done () <- atomically $ readTChan done return ()