Select in Idris
Our example demonstrates how to wait on multiple channel operations using a select-like construct in Idris. This is a powerful feature that combines effects and concurrency.
import Control.Concurrent
import Data.IORef
import System.Concurrency
main : IO ()
main = do
-- For our example we'll select across two channels.
c1 <- newIORef ""
c2 <- newIORef ""
-- Each channel will receive a value after some amount
-- of time, to simulate e.g. blocking RPC operations
-- executing in concurrent threads.
_ <- fork $ do
threadDelay 1000000 -- 1 second
writeIORef c1 "one"
_ <- fork $ do
threadDelay 2000000 -- 2 seconds
writeIORef c2 "two"
-- We'll use a loop to await both of these values
-- simultaneously, printing each one as it arrives.
forM_ [1..2] $ \_ -> do
selectIO [
do msg <- readIORef c1
when (msg /= "") $ putStrLn $ "received " ++ msg,
do msg <- readIORef c2
when (msg /= "") $ putStrLn $ "received " ++ msg
]
In this Idris version, we use IORef
s to simulate channels, and fork
to create concurrent threads. The selectIO
function is used to wait on multiple IO actions, similar to Go’s select
.
To run the program, you would compile it with the Idris compiler and then execute the resulting binary:
$ idris -o select select.idr
$ ./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 important to note that Idris doesn’t have built-in channels or a direct equivalent to Go’s select
statement. This example demonstrates a way to achieve similar functionality using Idris’s concurrency primitives and the selectIO
function from the System.Concurrency
module. The exact behavior may differ slightly from Go’s select
, especially in terms of fairness and randomness of selection.