If I have the following types and parser:
data Mode =
Mode1
| Mode2
deriving (Show, Eq, Read)
data ThingINeedMulitpleOf =
Thing { _name :: String, _mode :: Mode }
deriving (Show, Eq)
thingParser :: Parser ThingINeedMulitpleOf
thingParser = Thing <$> strArgument (metavar "NAME")
<*> option auto (long "mode" <> metavar "MODE")
and I build a parser in the following way:
data Config =
Config ThingINeedMulitpleOf ThingINeedMulitpleOf
deriving (Show, Eq)
loadConfig = execParser $ info (Config <$> thingParser <*> thingParser) fullDesc
then I can successfully parse my-exe Thing1 --mode Mode1 Thing2 --mode Mode2 but this is only useful if I want exactly two Things.
I'm running into problems when trying to change the Config to support n Things, ie:
data Config =
Config [ThingINeedMulitpleOf]
deriving (Show, Eq)
loadConfig = execParser $ info (Config <$> many thingParser) fullDesc
but I can now no longer parse my-exe Thing1 --mode Mode1 Thing2 --mode Mode2, giving me the error Invalid argument 'Thing1'
Interestingly, this works if the ThingINeedMulitpleOf only contains one field.
If you use a subparser with the Alternative typeclass's some function, you can get the effect you're looking for, admittedly with a slightly different command line syntax.
thingSubparser :: Parser ThingINeedMulitpleOf
thingSubparser = subparser $ command "thing" (info thingParser mempty)
loadConfig :: IO Config
loadConfig = execParser $ info (Config <$> some thingSubparser) fullDesc
With this you can write command lines like:
my-exe thing test --mode Mode1 thing test2 --mode Mode2
which yield the Config object:
Config [Thing {_name = "test", _mode = Mode1},Thing {_name = "test2", _mode = Mode2}]
I'm not quite sure why you need the subparser and can't just use some against the thingParser, but if I had to guess it'd be because the command gives the parser a delimiter (the "thing" argument/command name).
If you use a subparser with the Alternative typeclass's some function, you can get the effect you're looking for, admittedly with a slightly different command line syntax.
thingSubparser :: Parser ThingINeedMulitpleOf
thingSubparser = subparser $ command "thing" (info thingParser mempty)
loadConfig :: IO Config
loadConfig = execParser $ info (Config <$> some thingSubparser) fullDesc
With this you can write command lines like:
my-exe thing test --mode Mode1 thing test2 --mode Mode2
which yield the Config object:
Config [Thing {_name = "test", _mode = Mode1},Thing {_name = "test2", _mode = Mode2}]
I'm not quite sure why you need the subparser and can't just use some against the thingParser, but if I had to guess it'd be because the command gives the parser a delimiter (the "thing" argument/command name).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With