Michael Orlitzky | 24 Jul 03:01 2013

CmdArgs non-flag arguments with newtypes

I ran into an issue wrapping a [String] in a newtype with CmdArgs.
You're supposed to be able to declare that a field contains a list of
non-flag arguments... this works fine:

  data Cfg = Cfg { <whatever flags>, usernames :: [String] }
  arg_spec = Cfg { <whatever flags>, usernames = def &= args }
  ...

If I now call my program with,

  ./foo --flag1 --flag2 arg1 arg2

then usernames = [ "arg1", "arg2" ] as desired. However, I need to wrap
usernames in a newtype for an unrelated reason:

  newtype Usernames = Usernames [String]

Now, CmdArgs unexpectedly drops the first non-flag argument. So,

  ./foo --flag1 --flag2 arg1 arg2

gives me usernames = [ "arg2" ]. Obviously not what I want! Has anyone
else run into this? Figured out a workaround?
wren ng thornton | 24 Jul 05:48 2013

Re: CmdArgs non-flag arguments with newtypes

On 7/23/13 9:01 PM, Michael Orlitzky wrote:
> Obviously not what I want! Has anyone
> else run into this? Figured out a workaround?

I haven't run into this specific problem, but I do have a sort of
workaround. Whenever dealing with CmdArgs (or any similar system) I
typically define *two* record types.

The first one just gets the raw input from CmdArgs; no more, no less.
Thus, for your issue, this record would use String. For other issues
mentioned recently about optionality, this record would use Maybe.

The second one is the one actually used by the program as the
configuration object. This one is generated from the first by performing
various sanity checks, filling in defaults, converting types from their
CmdArgs version to the version I actually want, etc.

IME, regardless of language, trying to conflate these notions of an
external-facing parser-state and an internal-facing configuration-record
just causes problems and accidental complexity. It's best to keep them
separate IMO.

--

-- 
Live well,
~wren
Michael Orlitzky | 29 Jul 17:04 2013

Re: CmdArgs non-flag arguments with newtypes

On 07/23/2013 11:48 PM, wren ng thornton wrote:
> On 7/23/13 9:01 PM, Michael Orlitzky wrote:
>> Obviously not what I want! Has anyone
>> else run into this? Figured out a workaround?
> 
> I haven't run into this specific problem, but I do have a sort of
> workaround. Whenever dealing with CmdArgs (or any similar system) I
> typically define *two* record types.
> 
> The first one just gets the raw input from CmdArgs; no more, no less.
> Thus, for your issue, this record would use String. For other issues
> mentioned recently about optionality, this record would use Maybe.
> 
> The second one is the one actually used by the program as the
> configuration object. This one is generated from the first by performing
> various sanity checks, filling in defaults, converting types from their
> CmdArgs version to the version I actually want, etc.
> 
> IME, regardless of language, trying to conflate these notions of an
> external-facing parser-state and an internal-facing configuration-record
> just causes problems and accidental complexity. It's best to keep them
> separate IMO.
> 

It's not the internal configuration and command-line arguments that I
wanted to share, but rather the config /file/ and command-line
arguments. Those two are then mashed together into the real
configuration data structure at run time.

The reason for the newtype is for the config file parsing -- without the
(Continue reading)


Gmane