Schema definitions for the config-value package

Latest on Hackage:

This package is not currently in any snapshots. If you're interested in using it, we recommend adding it to Stackage Nightly. Doing so will make builds more reliable, and allow to host generated Haddocks.

ISC licensed by Eric Mertens
Maintained by


Hackage Build Status

Live Demo

The config-value and config-schema packages are available in a live demo.


This package allows the user to define configuration schemas suitable for matching against configuration files written in the config-value format. These schemas allow the user to extract an arbitrary Haskell value from an interpretation of a configuration file. It also allows the user to programatically generate documentation for the configuration files accepted by the loader.

{-# Language OverloadedStrings, ApplicativeDo #-}
module Example where

import qualified Data.Text as Text
import           Data.Text (Text)
import           Data.Monoid ((<>))
import           Data.Functor.Alt ((<!>))
import           Data.List.NonEmpty (NonEmpty)

import           Config
import           Config.Schema

exampleFile :: Text
exampleFile =
  " name: \"Johny Appleseed\" \n\
  \ age : 99                  \n\
  \ happy: yes                \n\
  \ kids:                     \n\
  \   * name: \"Bob\"         \n\
  \   * name: \"Tom\"         \n"

exampleValue :: Value Position
Right exampleValue = parse exampleFile

exampleSpec :: ValueSpecs Text
exampleSpec = sectionsSpec "" $
  do name  <- reqSection  "name" "Full name"
     age   <- reqSection  "age"  "Age of user"
     happy <- optSection' "happy" yesOrNo
              "Current happiness status"
     kids  <- reqSection' "kids"  (oneOrList kidSpec)
              "All children's names"

     return $
       let happyText = case happy of Just True  -> " and is happy"
                                     Just False -> " and is not happy"
                                     Nothing    -> " and is private"

       in name <> " is " <> Text.pack (show (age::Integer)) <>
             " years old and has kids " <>
             Text.intercalate ", " kids <>

kidSpec :: ValueSpecs Text
kidSpec = sectionsSpec "kid" (reqSection "name" "Kid's name")

-- | Matches the 'yes' and 'no' atoms
yesOrNo :: ValueSpecs Bool
yesOrNo = True  <$ atomSpec "yes" <!>
          False <$ atomSpec "no"

printDoc :: IO ()
printDoc = print (generateDocs exampleSpec)
-- *Example> printDoc
-- Top-level configuration file fields:
--     name: REQUIRED text
--        Full name
--     age: REQUIRED integer
--        Age of user
--     happy: `yes` or `no`
--        Current happiness status
--     kids: REQUIRED kid or list of kid
--        All children
-- kid
--     name: REQUIRED text
--        Kid's name

example :: Either (NonEmpty (LoadError Position)) Text
example = loadValue exampleSpec exampleValue
-- *Example> exampleVal
-- Right "Johny Appleseed is 99 years old and has kids Bob, Tom and is happy"


Revision history for config-schema

  • Support GHC 8.4.1

  • Add Spec instances for Int and Word types. All instances including the previous Int instance now validate ranges.
  • Changed argument order for loadValueFromFile

  • Add loadValueFromFile and SchemaError. This is intended as a quick way to get a configuration file loaded with all errors being thrown as exceptions.

  • Parameterize the Load module on a position type
  • Allow Docs module to process recursively defined specifications as long as a named section breaks the loop.
  • Add parentheses to docs when needed – 2017-05-17

  • Add support for GHC 7.10.3 – 2017-05-16

  • Allow generateDocs to work on any ValueSpec, rather than top-level empty-named section specs. – 2017-05-09

  • Added “association list” specifications
  • Use pretty library for documentation generation
  • Reorder parameters so that documentation comes last
  • Hide implementations of ValueSpecs and SectionSpecs – 2017-05-07

  • Expose liftValueSpec and liftSectionSpec
  • Add fractionalSpec
  • Add nonemptySpec and oneOrNonemptySpec
  • loadValue returns a NonEmpty LoadError – 2017-05-06

  • First version. Released on an unsuspecting world.
Used by 1 package:
comments powered byDisqus