Custom Errors in Haskell

In Haskell, we can create custom error types using data constructors. Here’s an example that demonstrates how to create and use custom errors:

import Control.Exception (Exception, throw, catch)
import Text.Printf (printf)

-- A custom error type usually has the suffix "Error".
data ArgError = ArgError
    { arg     :: Int
    , message :: String
    } deriving (Show)

-- Make ArgError an instance of Exception
instance Exception ArgError

-- Function that may throw our custom error
f :: Int -> Either ArgError Int
f arg
    | arg == 42 = Left $ ArgError arg "can't work with it"
    | otherwise = Right $ arg + 3

main :: IO ()
main = do
    -- Using `catch` to handle our custom error
    result <- catch (case f 42 of
                        Left e -> throw e
                        Right val -> return val)
              (\e -> do
                  let err = e :: ArgError
                  putStrLn $ printf "%d - %s" (arg err) (message err)
                  return (-1))
    
    print result

In this Haskell version:

  1. We define a custom ArgError type with arg and message fields.

  2. We make ArgError an instance of the Exception typeclass, which allows it to be thrown and caught.

  3. The f function returns an Either ArgError Int. It returns Left ArgError when the input is 42, otherwise it returns Right (arg + 3).

  4. In the main function, we use catch to handle our custom error. If an ArgError is thrown, we print its contents.

  5. Haskell doesn’t have a direct equivalent to Go’s errors.As, but we can achieve similar functionality using pattern matching in the catch clause.

To run the program:

$ ghc custom_errors.hs
$ ./custom_errors
42 - can't work with it
-1

This Haskell implementation showcases how to create and use custom error types, providing functionality similar to the original example while using idiomatic Haskell constructs.