Select in Haskell
Our example demonstrates the use of select
to wait on multiple channel operations. Combining concurrent operations with select is a powerful feature of this language.
import Control.Concurrent (forkIO, threadDelay)
import Control.Concurrent.Chan
import Control.Monad (forM_)
main :: IO ()
main = do
c1 <- newChan
c2 <- newChan
-- Each channel will receive a value after some amount
-- of time, to simulate e.g. blocking operations
-- executing concurrently.
forkIO $ do
threadDelay 1000000 -- 1 second
writeChan c1 "one"
forkIO $ do
threadDelay 2000000 -- 2 seconds
writeChan c2 "two"
-- We'll use `select` to await both of these values
-- simultaneously, printing each one as it arrives.
forM_ [1..2] $ \_ -> do
select
[ (c1, \msg -> putStrLn $ "received " ++ msg)
, (c2, \msg -> putStrLn $ "received " ++ msg)
]
-- Implement a simple select function
select :: [(Chan a, a -> IO ())] -> IO ()
select chans = do
result <- waitForFirst chans
case result of
Just (_, action, value) -> action value
Nothing -> return ()
waitForFirst :: [(Chan a, a -> IO ())] -> IO (Maybe (Chan a, a -> IO (), a))
waitForFirst [] = return Nothing
waitForFirst ((chan, action):rest) = do
value <- tryReadChan chan
case value of
Just v -> return $ Just (chan, action, v)
Nothing -> waitForFirst rest
In this example, we create two channels and start two concurrent operations that will write to these channels after a delay. We then use a select
-like function to await values from both channels simultaneously, printing each value as it arrives.
To run the program:
$ ghc -threaded select.hs
$ ./select
received one
received two
Note that the total execution time is only ~2 seconds since both the 1 and 2 second delays execute concurrently.
It’s worth noting that Haskell doesn’t have a built-in select
construct like some other languages. The select
function implemented here is a simplified version that demonstrates the concept. In practice, for more robust concurrent programming in Haskell, you might use libraries like async
or stm
which provide more sophisticated tools for managing concurrent operations.