Recover in Haskell

In Haskell, we don’t have a direct equivalent of Go’s panic and recover mechanism. However, we can simulate similar behavior using Haskell’s exception handling system. Here’s how we can implement a similar concept:

import Control.Exception
import System.IO.Unsafe

-- This function throws an exception
mayThrow :: IO ()
mayThrow = throwIO (userError "a problem")

-- Main function
main :: IO ()
main = do
    -- We use 'catch' to handle exceptions
    catch (do
        mayThrow
        -- This code will not run if mayThrow throws an exception
        putStrLn "After mayThrow()"
      ) (\e -> do
        -- This is our "recover" logic
        putStrLn $ "Recovered. Error:\n " ++ show (e :: SomeException)
      )

In Haskell, we use the Control.Exception module to handle exceptions, which is similar to Go’s panic and recover mechanism.

The mayThrow function simulates a function that might panic by throwing an exception using throwIO.

In the main function, we use catch to handle potential exceptions. The catch function takes two arguments:

  1. The action that might throw an exception (equivalent to the main body in the Go example).
  2. An exception handler (equivalent to the deferred function with recover in Go).

If mayThrow throws an exception, the execution will immediately jump to the exception handler, printing the error message. This is similar to how Go’s recover catches panics.

If no exception is thrown, the code after mayThrow would execute normally. However, in this case, it doesn’t because mayThrow always throws an exception.

To run this program:

$ runhaskell recover.hs
Recovered. Error:
 user error (a problem)

This demonstrates how we can achieve similar functionality to Go’s panic and recover in Haskell, albeit using a different mechanism (exceptions). While the syntax and exact behavior differ, the core concept of catching and handling unexpected errors remains the same.