Signals in Haskell
Here’s the translation of the Go code to Haskell, with explanations in Markdown format suitable for Hugo:
Our first example demonstrates how to handle Unix signals in Haskell. We’ll create a program that gracefully handles SIGINT and SIGTERM signals.
import System.Posix.Signals
import Control.Concurrent (forkIO, threadDelay)
import Control.Concurrent.MVar
main :: IO ()
main = do
-- Create an MVar to act as a signal between threads
done <- newEmptyMVar
-- Set up signal handlers
installHandler sigINT (Catch $ handleSignal "SIGINT" done) Nothing
installHandler sigTERM (Catch $ handleSignal "SIGTERM" done) Nothing
-- Fork a thread to simulate some work
forkIO $ do
putStrLn "Awaiting signal"
threadDelay 100000000 -- Sleep for 100 seconds
-- Wait for a signal
takeMVar done
putStrLn "Exiting"
handleSignal :: String -> MVar () -> IO ()
handleSignal sigName done = do
putStrLn $ "\nReceived " ++ sigName
putMVar done ()In this Haskell version, we use the System.Posix.Signals module to handle Unix signals. Here’s a breakdown of the code:
We import necessary modules for signal handling, concurrency, and inter-thread communication.
In the
mainfunction, we create anMVarcalleddone. This will act as a channel for signaling between threads.We set up signal handlers for SIGINT and SIGTERM using
installHandler. Each handler calls thehandleSignalfunction with the appropriate signal name and thedoneMVar.We fork a new thread that simulates some work by sleeping for 100 seconds. This is analogous to the main work of a server or long-running process.
The main thread then waits on the
doneMVar usingtakeMVar. This blocks until a signal is received and handled.The
handleSignalfunction prints the name of the received signal and puts a value into thedoneMVar, which unblocks the main thread.
When we run this program, it will block waiting for a signal. By typing Ctrl-C, we can send a SIGINT signal, causing the program to print the signal name and then exit.
$ runhaskell signals.hs
Awaiting signal
^C
Received SIGINT
ExitingThis Haskell implementation uses MVars for inter-thread communication, which is conceptually similar to channels in other languages. The forkIO function is used to create a new thread, analogous to goroutines in Go.
While the structure is different from the original Go code, this Haskell version achieves the same functionality of gracefully handling Unix signals.