logo
down
shadow

How do I create, and distinguish, global options using 'optparse-applicative'?


How do I create, and distinguish, global options using 'optparse-applicative'?

Content Index :

How do I create, and distinguish, global options using 'optparse-applicative'?
Tag : haskell , By : August
Date : November 28 2020, 04:01 AM

this one helps. As far as I know, this (in particular, the categorized help text) isn't really easy to do with optparse-applicative, since it isn't quite the pattern that they were planning for with global arguments. If you are okay with using program --global-options command --local-options (which is a fairly standard pattern) instead of program command --global-and-local-options, then you can use the approach shown in the linked example:
$ ./optparse-sub-example
optparse-sub-example - a small example program for optparse-applicative with
subcommands

Usage: optparse [--version] [--global-flag] COMMAND
  optparse subcommands example

Available options:
  -h,--help                Show this help text
  --version                Show version
  --global-flag            Set a global flag

Available commands:
  create                   Create a thing
  delete                   Delete the thing

$ ./optparse-sub-example --version create
0.0
$ ./optparse-sub-example --version delete
0.0
$ ./optparse-sub-example --global-flag create HI
Created the thing named HI
global flag: True
$ ./optparse-sub-example --global-flag delete
Deleted the thing!
global flag: True
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ApplicativeDo #-}

import Data.Monoid
import Data.Semigroup ((<>))
import Options.Applicative
import Options.Applicative.Types
data Opts = Opts
    { optGlobals :: !GlobalOpts 
    , optCommand :: !Command
    }
data GlobalOpts = GlobalOpts { optGlobalFlag :: Bool }
instance Semigroup GlobalOpts where
  -- Code for merging option parser results from the multiple parsers run
  -- at various different places. Note that this may be run with the default
  -- values returned by one parser (from a location with no options present)
  -- and the true option values from another, so it may be important
  -- to distinguish between "the default value" and "no option" (since "no
  -- option" shouldn't override another value provided earlier, while
  -- "user-supplied value that happens to match the default" probably should).
  --
  -- In this case this doesn't matter, since the flag being provided anywhere
  -- should be enough for it to be considered true.
  (GlobalOpts f1) <> (GlobalOpts f2) = GlobalOpts (f1 || f2)
instance Monoid GlobalOpts where
  -- Default values for the various options. These should probably match the
  -- defaults used in the option declarations.
  mempty = GlobalOpts False
data Command
    = Create String
    | Delete
mysubparser :: forall a b. Monoid a
            => Parser a
            -> Mod CommandFields b
            -> Parser (a, b)
mysubparser globals cmds = do
  g1 <- globals
  (g2, r) <- addGlobals $ hsubparser cmds
  pure (g1 <> g2, r)
  where 
        addGlobals :: forall c. Parser c -> Parser (a, c)
        addGlobals (NilP x) = NilP $ (mempty,) <$> x
        addGlobals (OptP (Option (CmdReader n cs g) ps)) =
          OptP (Option (CmdReader n cs $ fmap go . g) ps)
          where go pi = pi { infoParser = (,) <$> globals <*> infoParser pi }
        addGlobals (OptP o) = OptP ((mempty,) <$> o)
        addGlobals (AltP p1 p2) = AltP (addGlobals p1) (addGlobals p2)
        addGlobals (MultP p1 p2) =
          MultP ((\(g2, f) -> \(g1, x) -> (g1 <> g2, f x)) <$> addGlobals p1)
                (addGlobals p2)
        addGlobals (BindP p k) = BindP (addGlobals p) $ \(g1, x) ->
                                   BindP (addGlobals $ k x) $ \(g2, x') ->
                                     pure (g1 <> g2, x')
main :: IO ()
main = do
    (opts :: Opts) <- execParser optsParser
    case optCommand opts of
        Create name -> putStrLn ("Created the thing named " ++ name)
        Delete -> putStrLn "Deleted the thing!"
    putStrLn ("global flag: " ++ show (optGlobalFlag (optGlobals opts)))
  where
    optsParser :: ParserInfo Opts
    optsParser =
        info
            (helper <*> programOptions)
            (fullDesc <> progDesc "optparse subcommands example" <>
             header
                 "optparse-sub-example - a small example program for optparse-applicative with subcommands")
    versionOption :: Parser (a -> a)
    versionOption = infoOption "0.0" (long "version" <> help "Show version")
    globalOpts :: Parser GlobalOpts
    globalOpts = versionOption <*>
      (GlobalOpts <$> switch (long "global-flag" <> help "Set a global flag"))
    programOptions :: Parser Opts
    programOptions =
      uncurry Opts <$> mysubparser globalOpts (createCommand <> deleteCommand)
    createCommand :: Mod CommandFields Command
    createCommand =
        command
            "create"
            (info createOptions (progDesc "Create a thing"))
    createOptions :: Parser Command
    createOptions =
        Create <$>
        strArgument (metavar "NAME" <> help "Name of the thing to create")
    deleteCommand :: Mod CommandFields Command
    deleteCommand =
        command
            "delete"
            (info (pure Delete) (progDesc "Delete the thing"))
$ ./optparse-sub-example create --global-flag HI
Created the thing named HI
global flag: True
$ ./optparse-sub-example --global-flag create HI
Created the thing named HI
global flag: True
$ ./optparse-sub-example --global-flag delete
Deleted the thing!
global flag: True
$ ./optparse-sub-example delete --global-flag
Deleted the thing!
global flag: True
$ ./optparse-sub-example delete
Deleted the thing!
global flag: False
$ ./optparse-sub-example delete --version
0.0
$ ./optparse-sub-example create --version
0.0

Comments
No Comments Right Now !

Boards Message :
You Must Login Or Sign Up to Add Your Comments .

Share : facebook icon twitter icon

How do you provide a specific error message with optparse-applicative when multiple mutually exclusive options are provi


Tag : haskell , By : SachinJadhav
Date : March 29 2020, 07:55 AM
hope this fix your issue I'm not familiar with optparse-applicative, so I'm not sure what error-printing facilities it provides. (Sometimes parser combinator libraries offer a primitive that changes the error that's printed, but I didn't see anything for that on a quick skim of the optparse-applicative docs. Entirely possible that I missed it.)
But in case nothing is available from the library itself, you could always print your own message by accepting both flags; e.g.
data Exclusive = E1 | E2 | Both
exclusiveParser
     =  (flag' E1 (short 'e'))
    <|> (flag' E2 (short 'f'))
    <|> (flag' Both (short 'e') <* flag' Both (short 'f'))

optparse-applicative: Generate usage information with custom error message from options definition


Tag : haskell , By : Giles
Date : March 29 2020, 07:55 AM
wish help you to fix your issue It can be done using the parserFailure function from Options.Applicative.Extra:
renderError :: Context -> String -> IO ()                                       
renderError c msg = handleParseResult . Failure $                               
                        parserFailure argPrefs argInfo (ErrorMsg msg) [c]

Using optparse-applicative with multiple subcommands and global options


Tag : haskell , By : tjh0001
Date : March 29 2020, 07:55 AM
I hope this helps . I am writing a commandline program that takes multiple subcommands, which take flags/arguments. , The documentation you linked has this to say:
data Subcommand 
  = Upload { binary :: String } 
  | Search { regex  :: String } deriving Show 

data Options = Options 
  { configFile :: FilePath 
  , subcommand :: Subcommand 
  } deriving Show 

commandO = Options <$> configFileO <*> subcommandO 

configFileO = strOption
   ( long "configfile"
  <> help "Filepath of configuration file" 
   )

subcommandO :: Parser Subcommand
subcommandO = subparser ...
subcommandO = 
  subparser
    ( command "UPLOADFILE" (info uploadO
        ( progDesc "Upload a file" ))
   <> command "SEARCH" (info searchO
        ( progDesc "Search in a file" ))
   )

uploadO = Upload <$> 
  ( strOption
     ( long "binary"
    <> help "Binary file to upload" 
     )
  )

searchO = Upload <$> 
  ( strOption
     ( long "regex"
    <> help "Regular expression to search for" 
     )
  )

main = execParser opt >>= print where 
  opt = info (helper <*> commandO)
     ( fullDesc
    <> progDesc "Example for multiple subcommands"
    <> header "myProgram" )
>:main --configfile=~/.customrc UPLOADFILE --binary myfile.x
Options {configFile = "~/.customrc", subcommand = Upload {binary = "myfile.x"}}

>:main --configfile=~/.customrc SEARCH --regex "[a-z]+"
Options {configFile = "~/.customrc", subcommand = Upload {binary = "[a-z]+"}}

>:main --help
myProgram

Usage: <interactive> --configfile ARG COMMAND
  Example for multiple subcommands

Available options:
  -h,--help                Show this help text
  --configfile ARG         Filepath of configuration file

Available commands:
  UPLOADFILE               Upload a file
  SEARCH                   Search in a file
*** Exception: ExitSuccess

How to use options with multiple values with Haskell's optparse-applicative


Tag : haskell , By : Nandor Devai
Date : March 29 2020, 07:55 AM
it fixes the issue I think, the problem here is with the default value. Just remove value 1 from parser modifiers.
From docs on value:

Parsing user options into custom data types with OptParse-Applicative


Tag : haskell , By : greggerz
Date : March 29 2020, 07:55 AM
I wish this helpful for you In optparse-applicative there's the Parser type, but also the ParserInfo type which represents a "completed" parser holding extra information like header, footer, description, etc... and which is ready to be run with execParser. We go from Parser to ParserInfo by way of the info function which adds the extra information as modifiers.
Now, when writing a parser with subcommands, each subcommand must have its own ParserInfo value (implying that it can have its own local help and description).
data JournalCommand =
    JournalSearch String String
  | JournalReport String
  deriving (Show, Eq)

journalParserInfo :: O.ParserInfo JournalCommand
journalParserInfo = 
    let searchParserInfo :: O.ParserInfo JournalCommand
        searchParserInfo = 
            O.info
            (JournalSearch 
                <$> strArgument (metavar "ARG1" <> help "This is arg 1")
                <*> strArgument (metavar "ARG2" <> help "This is arg 2"))
            (O.fullDesc <> O.progDesc "desc 1")
        reportParserInfo :: O.ParserInfo JournalCommand
        reportParserInfo = 
            O.info
            (JournalReport 
                <$> strArgument (metavar "ARG3" <> help "This is arg 3"))
            (O.fullDesc <> O.progDesc "desc 2")
        toplevel :: O.Parser JournalCommand
        toplevel = O.subparser (mconcat [ 
                command "search" searchParserInfo, 
                command "journal" reportParserInfo 
            ])
     in O.info toplevel (O.fullDesc <> O.progDesc "toplevel desc") 
Related Posts Related QUESTIONS :
  • Haskell Input & Passing Values to Functions
  • Whats the difference between IO String and normal String in Haskell
  • What do I learn to "enlighten myself with the ways" of functional programming?
  • Compute all sublists with nth element removed
  • Does Idris have MaybeT?
  • Using the bind function to process a list
  • Giving function type signature inside typeclass instance gives an error
  • How can I use `throwM` with `Except`?
  • How to use atomicModifyIORef with impure functions?
  • Why does the type match on the next line but not on the same line in `do` block?
  • In Haskell apply sqrt in list of tuples
  • How does readIORef work: creates copy or it does not?
  • `f, g, h :: Kleisli ((->) e) a b` <=> `f >>> (g &&& h) = (f >>> g) &&&
  • Natural transformation as an argument in Haskell
  • Haskell: Using multiple let and return a value after the do block inside a function
  • Stack cache builds with various flags
  • What does "<-" mean?
  • Can someone explain to me what is wrong with the logic
  • MonadPlus IO isn't a monoid
  • How to prevent inputs being flushed into output?
  • Understanding the <$> operator
  • Different notions of weak head normal form?
  • Haskell IO action in `StateT a STM b`
  • How can Monoid r => Const r of the optic Fold type be generalized to Contravariant + Applicative?
  • Haskell stack - allow-newer enabled and won't turn off?
  • How to implement a Lens like Getter for a specific type?
  • Why function composition sometimes requires two "." 's to combine two functions
  • Finding equivalent program to proof in typed lambda calculus
  • How to define Linked list on Haskell?
  • How to check the double list length?
  • What are the rules regarding naming in Haskell?
  • How to determine if one can write a total, terminating Haskell function given a type?
  • Instantiate the Endofunctor type with the Show class
  • How to compose functions that return Bools to one function
  • Parse errors when using 'where' notation - how do I format this structure correctly?
  • How to store higher order function data in list in haskell?
  • Why is a typeclass constraint added when I did not define it in my original type definition?
  • Why is there difference between throw and throwIO?
  • Understanding foldr's definition
  • How to use Data.Data?
  • Overload (*) as a -> b -> c
  • Understanding the State Monad
  • Understanding fmap with a monad
  • Writing a flexible "string fetcher"
  • Understanding the filterM function
  • Why is main's return not an exit code?
  • Is main = return () a program?
  • Why can you create a value with "Just (+)"?
  • Haskell naive duplicate filtering
  • Understanding the writer type
  • pattern matching on constants
  • In Haskell, when using the XStrict language extension, is if short-circuiting?
  • Typeclasses and type inference in Haskell
  • Using foldr with only two parameters
  • The simplest way to generically traverse a tree in haskell
  • Is there a better way of writing indexof function?
  • Performance of Integer type with large numbers
  • Haskell: What does it mean for a type signature to be total?
  • Why doesn't `first` from Data.Bifunctor transform this value
  • Are all types declared with newtype phantom types
  • shadow
    Privacy Policy - Terms - Contact Us © scrbit.com