Timeouts in Haskell
Timeouts are important for programs that connect to external resources or that otherwise need to bound execution time. Implementing timeouts in Haskell can be achieved using the timeout
function from the System.Timeout
module.
import Control.Concurrent (threadDelay)
import System.Timeout (timeout)
import Control.Monad (void)
main :: IO ()
main = do
-- For our example, suppose we're executing an external
-- call that returns its result after 2s.
let slowOperation = do
threadDelay (2 * 1000000) -- 2 seconds
return "result 1"
-- Here we implement a timeout using the `timeout` function.
-- It will wait for 1 second for the result.
result1 <- timeout (1 * 1000000) slowOperation
case result1 of
Just res -> putStrLn res
Nothing -> putStrLn "timeout 1"
-- If we allow a longer timeout of 3s, then the operation
-- will succeed and we'll print the result.
let anotherSlowOperation = do
threadDelay (2 * 1000000) -- 2 seconds
return "result 2"
result2 <- timeout (3 * 1000000) anotherSlowOperation
case result2 of
Just res -> putStrLn res
Nothing -> putStrLn "timeout 2"
In this Haskell version:
We use
threadDelay
to simulate a slow operation. It takes microseconds as an argument, so we multiply seconds by 1,000,000.The
timeout
function fromSystem.Timeout
is used to implement the timeout mechanism. It takes a time in microseconds and an IO action, and returnsNothing
if the action doesn’t complete within the specified time, orJust result
if it does.We use pattern matching with
case
expressions to handle the results oftimeout
.Unlike in the original example, we don’t need to use channels or select statements, as Haskell’s
timeout
function provides a more straightforward way to implement timeouts.
Running this program shows the first operation timing out and the second succeeding:
$ runhaskell timeouts.hs
timeout 1
result 2
This example demonstrates how to implement timeouts in Haskell, which is useful for bounding the execution time of operations that might take too long to complete.