user656347
user656347

Reputation:

How to parse a product type partially

data Config = Config {
    a :: Bool,
    b :: Type1,
    c :: Type2
}

pA :: Parser Bool

pB :: Parser Type1

pC :: Parser Type2

pConfig :: Parser Config
pConfig = Config <$> pA <*> pB <*> pC

opts :: ParserInfo Config
opts = info (pConfig <**> helper)
       (fullDesc <> progDesc "My CLI" <> header "CLI executable")

main :: IO()
main = do
       (Config a b c) <- execParser opts
-- Populate a default config using a b c values

Is it possible to parse a product type partially? Config is a product type with member a, b and c and assume this comes from a library, so I cannot redefine this. I only want to parse a and b without caring about c. But, since a "Parser Config" can only have a construction like below

Config <$> pA <*> pB <*> pC

due to being a product type, if I do not give a "pC" it errors out. How to correctly handle this scenario?

Upvotes: 0

Views: 110

Answers (1)

Anders Kaseorg
Anders Kaseorg

Reputation: 3875

The Config <$> pA <*> pB <*> pC notation doesn’t care that Config is a constructor; you could have used any function of type Bool -> Type1 -> Type2 -> Config. If you don’t want to parse a Type2, you could use any function of type Bool -> Type1 -> Config.

config' :: Bool -> Type1 -> Config
config' a b c = Config a b someDefaultType2

pConfig :: Parser Config
pConfig = config' <$> pA <*> pB

Equivalently, you stick with the Config constructor but connect a pure value instead of a parser to its third argument.

pConfig :: Parser Config
pConfig = Config <$> pA <*> pB <*> pure someDefaultType2

(Either way, you do need to have some way of providing a value of Type2, if you want to get a Config out.)

Upvotes: 2

Related Questions