+
+{- $example1
+
+A simple choice for the type associated with flags is to define a type
+@Flag@ as an algebraic type representing the possible flags and their
+arguments:
+
+> module Opts1 where
+>
+> import System.Console.GetOpt
+> import Data.Maybe ( fromMaybe )
+>
+> data Flag
+> = Verbose | Version
+> | Input String | Output String | LibDir String
+> deriving Show
+>
+> options :: [OptDescr Flag]
+> options =
+> [ Option ['v'] ["verbose"] (NoArg Verbose) "chatty output on stderr"
+> , Option ['V','?'] ["version"] (NoArg Version) "show version number"
+> , Option ['o'] ["output"] (OptArg outp "FILE") "output FILE"
+> , Option ['c'] [] (OptArg inp "FILE") "input FILE"
+> , Option ['L'] ["libdir"] (ReqArg LibDir "DIR") "library directory"
+> ]
+>
+> inp,outp :: Maybe String -> Flag
+> outp = Output . fromMaybe "stdout"
+> inp = Input . fromMaybe "stdin"
+>
+> compilerOpts :: [String] -> IO ([Flag], [String])
+> compilerOpts argv =
+> case getOpt Permute options argv of
+> (o,n,[] ) -> return (o,n)
+> (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options))
+> where header = "Usage: ic [OPTION...] files..."
+
+Then the rest of the program will use the constructed list of flags
+to determine it\'s behaviour.
+
+-}
+
+{- $example2
+
+A different approach is to group the option values in a record of type
+@Options@, and have each flag yield a function of type
+@Options -> Options@ transforming this record.
+
+> module Opts2 where
+>
+> import System.Console.GetOpt
+> import Data.Maybe ( fromMaybe )
+>
+> data Options = Options
+> { optVerbose :: Bool
+> , optShowVersion :: Bool
+> , optOutput :: Maybe FilePath
+> , optInput :: Maybe FilePath
+> , optLibDirs :: [FilePath]
+> } deriving Show
+>
+> defaultOptions = Options
+> { optVerbose = False
+> , optShowVersion = False
+> , optOutput = Nothing
+> , optInput = Nothing
+> , optLibDirs = []
+> }
+>
+> options :: [OptDescr (Options -> Options)]
+> options =
+> [ Option ['v'] ["verbose"]
+> (NoArg (\ opts -> opts { optVerbose = True }))
+> "chatty output on stderr"
+> , Option ['V','?'] ["version"]
+> (NoArg (\ opts -> opts { optShowVersion = True }))
+> "show version number"
+> , Option ['o'] ["output"]
+> (OptArg ((\ f opts -> opts { optOutput = Just f }) . fromMaybe "output")
+> "FILE")
+> "output FILE"
+> , Option ['c'] []
+> (OptArg ((\ f opts -> opts { optInput = Just f }) . fromMaybe "input")
+> "FILE")
+> "input FILE"
+> , Option ['L'] ["libdir"]
+> (ReqArg (\ d opts -> opts { optLibDirs = optLibDirs opts ++ [d] }) "DIR")
+> "library directory"
+> ]
+>
+> compilerOpts :: [String] -> IO (Options, [String])
+> compilerOpts argv =
+> case getOpt Permute options argv of
+> (o,n,[] ) -> return (foldl (flip id) defaultOptions o, n)
+> (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options))
+> where header = "Usage: ic [OPTION...] files..."
+
+Similarly, each flag could yield a monadic function transforming a record,
+of type @Options -> IO Options@ (or any other monad), allowing option
+processing to perform actions of the chosen monad, e.g. printing help or
+version messages, checking that file arguments exist, etc.
+
+-}