[Haskell-cafe] Re: Avoiding boilerplate retrieving GetOpt cmd line args

Dave Bayer bayer at math.columbia.edu
Fri Jul 27 11:14:02 EDT 2007


Neil Mitchell <ndmitchell <at> gmail.com> writes:

> then lookup, instead of just "" as the else clause.

Thanks, all. After digesting what was on this thread as I woke up this
morning, I ended up writing something rather close to this.

I have a reusable wrapper around System.Console.GetOpt that adds

> type Opt a = (a,String)
> 
> noArg :: a -> ArgDescr (Opt a)
> noArg x = NoArg (x,"")
> 
> reqArg :: a -> String -> ArgDescr (Opt a)
> reqArg x s = ReqArg f s
>     where f y = (x,y)
> 
> optArg :: a -> String -> ArgDescr (Opt a)
> optArg x s = OptArg f s
>     where f (Just y) = (x,y)
>           f Nothing  = (x,"")
> 
> isOption :: Eq a => a -> [Opt a] -> Bool
> isOption opt assoc =  case lookup opt assoc of
>     Nothing -> False
>     Just _  -> True
> 
> getOption :: Eq a => a -> [Opt a] -> String
> getOption opt assoc = case lookup opt assoc of
>     Nothing -> ""
>     Just s  -> s

Then in a project-specific module I write

> data Flag
>     = Filter
>     | DateFormat
>     | DocStart
>     | DocEnd
>     | ForceStyle
>     | Help
>     deriving (Eq)
> 
> defaults :: [Opt Flag]
> defaults =
>     [ (Filter,     "Markdown.pl")
>     , (DateFormat, "%B %e, %Y")
>     , (DocStart,   "^\\s*{-\\s*$")
>     , (DocEnd,     "^\\s*-}\\s*$")
>     ]
> 
> flags :: [OptDescr (Opt Flag)]
> flags =
>     [ Option ['s'] ["style"]  (noArg ForceStyle)
>         "Overwrite existing style.css"
>     , Option ['m'] ["markup"] (reqArg Filter "path")
>         "Path to Markdown-style markup filter"
>     , Option ['d'] ["date"]   (reqArg DateFormat "format")
>         "Unix-style modification date format"
>     , Option ['a'] ["start"]  (reqArg DocStart "string")
>         "Documentation start string"
>     , Option ['b'] ["end"]    (reqArg DocEnd "string")
>         "Documentation end string"
>     , Option ['h'] ["help"]   (noArg Help)
>         "Print this help message"
>     ]

which looks "almost" like the sample code I started with. Reading quickly,
one might miss the case change from `NoArg` to `noArg`, etc.

This is simple, and it works, with less option-specific boilerplate. One
could imagine generating `flags` automatically from an extension of
`defaults`, but I'm content to move on.

The relevant code is at

http://www.math.columbia.edu/~bayer/Haskell/Annote/GetOpt.html
http://www.math.columbia.edu/~bayer/Haskell/Annote/Flags.html
http://www.math.columbia.edu/~bayer/Haskell/Annote/Main.html




More information about the Haskell-Cafe mailing list