haskellcommand-line-argumentsapplicativeoptparse-applicative

How to parse an optional flag as a Maybe value?


I'm trying to use optparse-applicative to parse a Maybe String but I can't find anywhere how to deal with Maybe. The only thing I found is to add a default value but I really need a Nothing if user didn't supply an option instead of "". Is there any way to achieve this ?

Here is an example of working code:

import Options.Applicative

data Config = Config
    { cIn :: String
    , cOut :: String
    } deriving Show

configParser :: Parser Config
configParser = Config
    <$> strOption (long "in" <> short 'i')
    <*> strOption (long "out" <> short 'o')


main :: IO ()
main = do
    conf <- execParser (info configParser fullDesc)
    print conf

However, I would like the parameters to be optional and use Maybe String instead of String in Config :

data Config = Config
    { cIn :: Maybe String
    , cOut :: Maybe String
    } deriving Show

Solution

  • See the following passage of the optparse-applicative README:

    Parsers are instances of both Applicative and Alternative, and work with any generic combinator, like many and some. For example, to make a option return Nothing instead of failing when it's not supplied, you can use the optional combinator in Control.Applicative:

    optional $ strOption
       ( long "output"
      <> metavar "DIRECTORY" )
    

    Accordingly, all you have to do is apply the optional combinator to the result of strOption:

    import Options.Applicative
    
    data Config = Config
        { cIn  :: Maybe String
        , cOut :: Maybe String
        } deriving Show
    
    configParser :: Parser Config
    configParser = Config
        <$> (optional $ strOption $ long "in" <> short 'i')
        <*> (optional $ strOption $ long "out" <> short 'o')
    
    main :: IO ()
    main = do
        conf <- execParser (info configParser fullDesc)
        print conf
    

    Tests at the command line:

    $ main --in foo -o bar
    Config {cIn = Just "foo", cOut = Just "bar"}
    $ main -i foo
    Config {cIn = Just "foo", cOut = Nothing}