This post announces and showcases yamlparse-applicative.
I am a long-time user of optparse-applicative and am very happy and impressed with it. I particularly like that it does not just handle the parsing of arguments, but it also takes care of documenting the parser that you write automatically. Here is an example output for optparse-applicative:
Usage: intray COMMAND [--config-file FILEPATH] [--url URL]
[--cache-dir FILEPATH] [--data-dir FILEPATH] ([--no-sync] |
[--sync])
Available options:
-h,--help Show this help text
--config-file FILEPATH Give the path to an altenative config file
--url URL The url of the server.
--cache-dir FILEPATH The directory to use for caching
--data-dir FILEPATH The directory to use for data
--no-sync Do not try to sync.
--sync Definitely try to sync.
It is beautiful and self-evident to write arguments that would satisfy this parser. However, when it comes to parsing the (Yaml) config files that the same program would read, things were not so easy. After I had written the yaml parser, I would quickly forget how to write a configuration file that would satisfy the parser.
I procrastinated writing documentation for my config file format for a while. At some point my procrastination in writing documentation just became too much for me to handle, and I made yamlparse-applicative instead.
A parser with two functions
Instead of using FromJSON to parse your config file using yaml and then writing documentation for your format, yamlparse-applicative combines those two functions into one type.
A yamlparse-applicative parser allows both actual parsing and generating documentation about what it does. In code, there exists a type Parser i o and these two functions:
data Parser i o where
[...]
implementParser :: Parser i o -> (i -> Data.Yaml.Parser o)
explainParser :: Parser i o -> SchemaNow you can use a single value of type Parser Yaml.Value FooBar to both parse a FooBar from a Yaml.Value, and to generate a schema that describes how to write a Yaml value that will satisfy this parser.
Usage example
Let's look at an example of a configuration file that is parsed into a value of type Configuration:
data Configuration
{ confPort :: Int
, confHost :: Maybe Text
}I will not even describe what the fields of this type do here, because we will document them as part of the implementation of the yaml parser:
instance YamlSchema Configuration where
yamlSchema =
objectParser "Configuration" $ -- Configuration is an object within the yaml file
Configuration
<$> optionalFieldWithDefault "port" 8000 "The port to serve web requests on"
<*> optionalField "host" "The host to serve web requests on"Now we can get a FromJSON instance for free:
instance FromJSON Configuration where
parseJSON = viaYamlSchemaWe can generate the following documentation automatically using prettySchemaDoc:
# Configuration
port: # optional, default: 8000
# The port to serve web requests on
<number>
host: # optional
# The host to serve web requests on
<string>We can even get syntax-highlighted documentation using prettyColourisedSchemaDoc:

References
This package can be used via Hackage, Stackage and the source is on GitHub.