Это возможно, с небольшими изменениями, двумя разными способами:
- Вы можете создать синтаксический анализатор, который разрешает
-b
только в том случае, если у вас есть -a
, но вы не можете настаивать на том, чтобы -a
стояло первым, поскольку комбинатор <*>
в optparse-applicative не определяет порядок.
- Вы можете настаивать на том, чтобы опция
-b
следовала за опцией a
, но вы делаете это, реализуя a
как команду, поэтому вы теряете -
перед ней.
Applicative определенно достаточно силен для этого, поскольку нет необходимости проверять значения, возвращаемые синтаксическими анализаторами, чтобы определить, разрешено ли -b
, поэтому >>=
не требуется; Если -a
завершается успешно с любым выводом, -b
разрешается.
Примеры
Я буду использовать тип данных, чтобы представить, какие аргументы присутствуют, но на самом деле они были бы более значимыми.
import Options.Applicative
data A = A (Maybe B) deriving Show
data B = B deriving Show
Таким образом, опции нашей программы могут содержать букву А, которая может иметь букву В, и всегда содержать строку.
boption :: Parser (Maybe B)
boption = flag Nothing (Just B) (short 'b')
Способ 1: стандартные комбинаторы - -b
может идти только с -a
(любой порядок)
Я буду использовать flag' () (short 'a')
, который просто настаивает на том, что -a
существует, но затем использую *>
вместо <*>
, чтобы игнорировать возвращаемое значение ()
и просто возвращать то, что возвращает синтаксический анализатор boption
, предоставляя опции -a [-b]
. Затем я отмечу это A :: Maybe B -> A
и, наконец, сделаю все это optional
, так что у вас есть варианты [-a [-b]]
aoption :: Parser (Maybe A)
aoption = optional $ A <$> (flag' () (short 'a' ) *> boption)
main = execParser (info (helper <*> aoption)
(fullDesc <> progDesc "-b is only valid with -a"))
>>= print
Обратите внимание, что поскольку <*>
допускает любой порядок, мы можем поставить -a
после -b
(что не совсем то, о чем вы просили, но работает нормально и имеет смысл для некоторых приложений).
ghci> :main -a
Just (A Nothing)
ghci> :main -a -b
Just (A (Just B))
ghci> :main -b -a
Just (A (Just B))
ghci> :main -b
Usage: <interactive> [-a] [-b]
-b is only valid with -a
*** Exception: ExitFailure 1
Способ 2: подпарсер команды - -b
может следовать только за a
Вы можете использовать command
для создания subparser
, который действителен только при наличии командной строки. Вы можете использовать его для обработки аргументов, как это делает Cabal, так что cabal install
и cabal update
имеют совершенно разные параметры. Поскольку command
принимает аргумент ParserInfo
, можно использовать любой синтаксический анализатор, который вы можете передать execParser
, так что вы можете вкладывать команды сколь угодно глубоко. К сожалению, команды не могут начинаться с -
, поэтому будет program [a [-b]] ...
вместо program [-a [-b]] ...
.
acommand :: Parser A
acommand = subparser $ command "a" (info (A <$> (helper <*> boption))
(progDesc "you can '-b' if you like with 'a'"))
main = execParser (info (helper <*> optional acommand) fullDesc) >>= print
Который работает следующим образом:
ghci> :main
Nothing
ghci> :main a
Just (A Nothing)
ghci> :main a -b
Just (A (Just B))
ghci> :main -b a
Usage: <interactive> [COMMAND]
*** Exception: ExitFailure 1
Поэтому перед -b
нужно поставить a
.
person
AndrewC
schedule
10.08.2014