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

Jonathan Cast jcast at ou.edu
Fri Jul 27 09:52:28 EDT 2007


On Friday 27 July 2007, Dave Bayer wrote:
> Ok, I'm writing a command line tool, using System.Console.GetOpt to
> handle command line arguments. My Flags structure so far is
>
> > data Flag
> >     = Filter String
> >
> >     | DateFormat String
> >     | DocStart String
> >     | DocEnd String
>
> ...
>
> and I want to write accessor functions that return the strings if
> specified, otherwise returning a default. The best I've been able to
>
> do is this:
> > getFilter = getString f "Markdown.pl"
> >     where f (Filter s) = Just s
> >           f _ = Nothing
> >
> > getDateFormat = getString f "%B %e, %Y"
> >     where f (DateFormat s) = Just s
> >           f _ = Nothing
> >
> > getDocStart = getString f "^{-$"
> >     where f (DocStart s) = Just s
> >           f _ = Nothing
> >
> > getDocEnd = getString f "^-}$"
> >     where f (DocEnd s) = Just s
> >           f _ = Nothing
>
> using a generic accessor function `getString`.
>
> There are eight (and growing) needless lines here, where what I
> really want to do is to pass the constructors `Filter`, `DateFormat`,
> `DocStart`, or `DocEnd` to the function `getString`. ghci types each
> of these as `String -> Flag`, so one at least knows how to type such
> a `getString`, but using a constructor-passed-as-an-argument in a
> pattern match is of course a "Parse error in pattern". (I expected as
> much, but I had to try... `String -> Flag` is not enough information
> to make it clear we're passing a constructor, rather than some hairy
> arbitrary function, so such a pattern match would be undecidable in
> general.)
>
> So what's the right idiom for avoiding this boilerplate?

What you want can (almost) be done as follows:

{-# OPTIONS_GHC -fglasgow-exts #-}
import Data.Generics
import Data.Typeable

data Flag
  = Filter String
  | DateFormat String
  | DocStart String
  | DocEnd String
  deriving (Typeable, Data)

getString :: Flag -> String -> Flag -> String
getString c df f | toConstr c /= toConstr f = df
getString c df (Filter s) = s
getString c df (DateFormat s) = s
getString c df (DocStart s) = s
getString c df (DocEnd s) = s

This version uses overlapping patterns, of course; it should be evident how to 
change that if you want.

Call it as

getString Filter{} "Markdown.pl" flag

Jonathan Cast
http://sourceforge.net/projects/fid-core
http://sourceforge.net/projects/fid-emacs
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://www.haskell.org/pipermail/haskell-cafe/attachments/20070727/65beda62/attachment.bin


More information about the Haskell-Cafe mailing list