h,umn      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                                                                         0.0.2.2 Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>cfg0A custom error message for non-top-level recordscfgA type level predicate that helps us identify top level product typescfgA type level helper for creating custom error messages based on a predicate Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<> + cfg7Represents all possible kinds of configuration options. cfg#Options for manipulating a root keycfgType that represents a decision between using the type constructor name or the data constructor name as the root key.This type is polymorphic so that we can use it to contain a term level text transformation for root keys, as well as be used at the type level parameterized by a type that defines the key modifiers to use.cfg/Options that pertain to record field accessors.cfgDefault key options, does no transformation to record field accessors.cfgDefault root key option, uses the type constructor name for the root key and applies no transformations to the root key or keys derived from record fields.cfgDefaults to regular  (not  )cfgHelper function that allows us to generically extract the record field modifiers from either a   or a  record.     Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>cfg=This typeclass turns a type level "tag" into a function from  Text -> Text. In addition to the instances for the "tags", there are also instances for type level lists and tuples up to an arity of 4. important: For type level lists and tuples the modifiers are applied in order from left to right.1getKeyModifier @'[ToUpper, ToLower] "Hello World" "hello world"0getKeyModifier @(ToLower, ToUpper) "Hello World" "HELLO WORLD".getKeyModifier @CamelToSnake "iLoveCFGProject""i_love_cfg_project"cfgSpecialized version of = where the separator is "-". Results in kebab cased strings.cfgSpecialized version of = where the separator is "_". Results in snake cased strings.cfgTakes a type level character known as the "separator" and will break the camel case string on its "humps" and then rejoin the string with the separator.cfgTakes a type level string and removes that from the end of the text, corresponds to 'Data.Text.stripSuffix. cfgTakes a type level string and removes that from the beginning of the text, corresponds to .!cfg0Upper cases the first character, corresponds to ."cfg0Lower cases the first character, corresponds to .#cfg8Upper cases all alphabetical characters, corresponds to .$cfg8Lower cases all alphabetical characters, corresponds to .%cfg(Identity transformation, corresponds to , does not change the string.&cfg,Map over the first character of a stream of 'cfgFunction for breaking a camel case string on its "humps" and re-joining on a provided separator char.(cfgData.Text.Text version of ''cfgSeparator charactercfgCamel cased string'(&%" $#!%$#"! &'( Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>9cfgThis class lets us represent defaults as a function from record field names to  values. Nothing represents the absence of a default, and the default implementation is to always return Nothing.:cfgRecord field labelcfgSerialized default;9:9:; Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<><cfgType alias for a subtree=cfgType alias for our internal tree structure. If this was written directly as a sum type it would look like this: /Pure value | Free (Map key (KeyTree key value))>cfgRight fold on a =. Uses  under the hood.?cfg/A fold that appends a value at the leaf of the =, identifies what to insert at the leaf by running a function on an accumulated value.@cfg/A fold that appends a value at the leaf of the = (like ?4), but the function on the accumulator can return a  . In the Nothing case we just append a  full of an empty .AcfgLike ?7 but with functions that return a value wrapped in an  effect f?. The function is suffixed with "Traverse" because we use the % to wrap the entire tree in a single  effect.Bcfg Similar to A except the  effect can optionally return a result. The function is manually implemented rather than using * methods so that we don't have to require  on f-. This allows consumers to use effects like  that don't have a  instance.>cfgFunction to run on  valuescfgStep function for foldcfgInitial accumulatorcfgKeyTree to fold?cfgFunction to run on existing  leaves a is the accumulator v is the value in Pure.cfgFunction from accumulator a to a value v.. This happens when an empty subtree is found.cfg Step function for fold with key k as an argument.cfg Accumulator.cfgKeyTree to append values to.@cfgFunction to run on existing  leaves.cfg,Function to run when an empty node is found.cfg Step function for fold with key k as an argument.cfg Accumulator.cfgTree to be folded.AcfgFunction to run on existing  leaves.cfg,Function to run when an empty node is found.cfg Step function for fold with key k as an argument.cfg Accumulator.cfgTree to be folded. ?A>@B<= =<>?@AB Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone("%&')*-/01369<=>&?CcfgThis is a text parser that we use to parse the eventual values we get from a configuration.EcfgThis is the instance that allows us to parse a result from our configuration source after we have retrieved it.FcfgTakes in the tree representation of our configuration and parses out our Haskell type)The default instance allows us to wrap a C in a E, this allows us to use a uniform typeclass for parsing, but at the same time distinguish between traversing the key structure and actually parsing the textual value.Gcfg)Type errors we can encounter when parsingHcfgWe encountered a  that was missing a key.Icfg!Expected to find a subtree aka a + with a map in it, but instead we found a .JcfgExpected to find a ) with a value but instead found a subtreeKcfgRan a D and was unable to parse valueLcfg$Type alias for our megaparsec parsercfgLexer parser helper.cfgcfgcfgcfgcfgcfgcfgMcfgNcfgOcfgPcfgQcfgRcfgScfgTcfgUcfgVcfgWcfgXcfgYcfgZcfg[cfg\cfg]cfg^cfg_cfg`cfgacfgbcfgccfgecfgfcfggcfghcfgicfgjcfgkcfglcfgmcfgncfgocfgpcfgqcfgrcfgscfgtcfgucfgvcfgwcfgxcfgycfgzcfg{cfg|cfgHcfg'The record field name that was missing.cfg&The subtree that was missing an entry.IcfgThe key that was missingcfgThe value that was foundJcfg"The subtree that was found insteadKcfgThe parser errord GIJHKEFLCD EFdCDLGHIJK Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>) cfgThis is a generic version of cfgThis is the function that hooks into the generic machinery. It is called by the deriving mechanism in Cfg.Deriving.Value.cfgThis is also an important instance for product types with unnamed fields that are intended to be parsed as values (not nested configurations).cfgThis is the main instance, which distributs a value parser over a sum type using retry and alternative.cfgcfgcfgcfgcfgcfg Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>1!cfg%This class is the generic version of E. It recurses on the generic structure of a type, building up a return type for the parser.cfgThis function is the workhorse of the generic machinery, however the user should never have to invoke it directly. Instead, one of the newtypes from 8 should call into this function in the definition of a 6 instance. The deriving via type should pull out the   from type level information.cfgThis is the product case, we just distribute the parsers over the different product fields.Notably, there is no sum type case. We could potentially add that in the future, allowing users to specify different cases of configuration. But right now that seems like it would be more confusing than helpful, so we just give a type error by eliding the instance.cfgThis is the most important case, we need to look up the subconfig by key (just the record field with all key modifiers applied), and then recursively parse the sub tree.cfg=This is the data constructor case, if we are dealing with a    instance, then we have lookup the "root key", but in all other cases we just keep recursing.cfg=This is the type constructor case, if we are dealing with a    instance, then we have lookup the "root key", but in all other cases we just keep recursing.cfgThis is the "base case", since  GHC.Generics; don't recurse the generic represetation multiple levels, a* is just a plain type. Therefore we call F on it. a. may be another nested record, in which case  will probably get called again, but for the generic representation of a sub-tree. Or it will find the default instance for E (indicating that we have reached a leaf) and dispatch to a value parser through F.  Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>3CcfgThis newtype is used to derive C instances for your types using the deriving via mechanism. In general this should be used for sum types, and product types without named fields (i.e. not records). The majority of the types that you would want as values should have instances in  Cfg.Source and  Cfg.Parser.cfgcfgcfg  Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>7`cfgThis is the instance that allows us to construct a tree representation of type a based on its structure.cfgSince the structure of a is statically known this  can be thought of as a constant, no runtime computation required!cfgThis type alias represents a function that fetches values from an external configuration source and inserts them into the leaves of our cfgBase case for , inserts an empty map that indicates we are "expecting a value here"cfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfg  Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>BcfgThis class is the generic version of 'ConfigSource. It recurses on the generic structure of a type, building up = representation.cfgThis function is used by the deriving via machinery to dispatch to the generic machinery, the user should never have to invoke it directly. This takes in a   which are retrieved from the deriving via newtypes, and also threads a 9. instance through so that we can dispatch to : in the  case.cfg+Sum types should represent base values, so  Free M.empty is the right thing to do here, although we should probably never hit this case, since sum types should be nested under record fields as base values.cfgThis instance handles product types and is pretty important. We need to check that recursive calls to 6 generate sub-trees, and then we merge the sub-trees.*You may wonder what happens if there is a  value in one of the record fields, well that would be represented like so: *Free $ M.singleton fieldName (Pure value) since we need to account for the key corresponding to the record field. So we really should never hit a case were a recursive call to  yields a raw .cfg=This is the type constructor case, if we are dealing with a    instance, then we have to create an extra layer with the "root key" as a key and then a subtree (calculated by recursively calling ) as the value.cfg=This is the data constructor case, if we are dealing with a    instance, then we have to create an extra layer with the "root key" as a key and then a subtree (calculated by recursively calling ) as the value.cfgThis instance is important because it does the work of pulling off the field selector name, and creating a sub-tree under that key by calling  recursively. If there is a default for that selector then no sub-tree is created, instead we insert a "placeholder" value tagged by - to represent that it is the end of the tree.)We detect if a default exists by calling : from the 9 instance on the selector, defaults is of type Text -> Maybe Text , so the Nothing case indicates no default.cfgThis is the "base case", since  GHC.Generics; don't recurse the generic represetation multiple levels, a* is just a plain type. Therefore we call  on it. a. may be another nested record, in which case ! will probably get called again, but for the generic representation of a sub-tree. It will do this until it finds a  instance for  " which will just add a 'Free Data.Map.empty' (indicating a hole to be filled when we fetch the configuration).  Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>Zcfg1Typeclass for reifying type level arguments into #cfg=Typeclass for reifying type level field label modifiers into $cfgThis newtype is used to derive instances for your root configuration type (i.e. the top level record for all your configuration). The only additional functionality that it provides is that it lets you specify a root key, which is derived from either the type name or the data constructor name. You choose which name you select by providing either % or & as the first type argument to . These ' types also take a type level argument where you can provide key modifiers, if you don't want to apply any key modifiers you can pass in (0 or an empty tuple or an empty type level list.TypeName Example"import GHC.Generics (Generic (..))$import Cfg.Source (ConfigSource(..))$import Cfg.Parser (ConfigParser(..))'import Cfg.Deriving.Config (Config(..))-import Cfg.Source.Default (DefaultSource(..))import Cfg.Deriving.KeyModifier:{ 'data TypeNameConfig = ConfigConstructor { appConfigSetting1 :: Int , appConfigSetting2 :: Bool , appConfigSetting3 :: String }) deriving (Generic, Show, DefaultSource)' deriving (ConfigSource, ConfigParser) via ConfigRoot ('TypeName '[StripSuffix "Config", CamelToSnake, ToUpper])2 '[StripPrefix "app", CamelToSnake, ToUpper] TypeNameConfig:}%pPrint $ configSource @TypeNameConfigFree ( fromList [ ( "TYPE_NAME" , Free ( fromList [+ ( "CONFIG_SETTING1" , Free+ ( fromList [] ) ) ,+ ( "CONFIG_SETTING2" , Free+ ( fromList [] ) ) ,+ ( "CONFIG_SETTING3" , Free+ ( fromList [] ) ) ] ) ) ] )ConstructorName Example:{ 'data TypeNameConfig = ConfigConstructor { appConfigSetting1 :: Int , appConfigSetting2 :: Bool , appConfigSetting3 :: String }) deriving (Generic, Show, DefaultSource)' deriving (ConfigSource, ConfigParser) via ConfigRoot" ('ConstructorName Identity)2 '[StripPrefix "app", CamelToSnake, ToUpper] TypeNameConfig:}%pPrint $ configSource @TypeNameConfigFree ( fromList [! ( "ConfigConstructor" , Free ( fromList [+ ( "CONFIG_SETTING1" , Free+ ( fromList [] ) ) ,+ ( "CONFIG_SETTING2" , Free+ ( fromList [] ) ) ,+ ( "CONFIG_SETTING3" , Free+ ( fromList [] ) ) ] ) ) ] )cfgThis newtype is identical to  except that it accepts a type argument which can be used to apply a )1 to each record field name when generating keys.Example"import GHC.Generics (Generic (..))$import Cfg.Source (ConfigSource(..))$import Cfg.Parser (ConfigParser(..))'import Cfg.Deriving.Config (Config(..))-import Cfg.Source.Default (DefaultSource(..)):{ data AppConfig = AppConfig { appConfigSetting1 :: Int , appConfigSetting2 :: Bool , appConfigSetting3 :: String }) deriving (Generic, Show, DefaultSource)' deriving (ConfigSource, ConfigParser) via (ConfigOpts '[StripPrefix "app", CamelToSnake, ToUpper] AppConfig):} pPrint $ configSource @AppConfigFree ( fromList [ ( "CONFIG_SETTING1" , Free ( fromList [] ) ) , ( "CONFIG_SETTING2" , Free ( fromList [] ) ) , ( "CONFIG_SETTING3" , Free ( fromList [] ) ) ] )cfgThis newtype is the simplest deriving option. It doesn't allow you to alter key names with a ), it only specifies record fields as keys within the configuration tree hierarchy. Therefore it is not possible to derive this for configuration values (such as product types without named record fields, or sum types), only top level records.Example"import GHC.Generics (Generic (..))$import Cfg.Source (ConfigSource(..))$import Cfg.Parser (ConfigParser(..))'import Cfg.Deriving.Config (Config(..))-import Cfg.Source.Default (DefaultSource(..)):{data AppConfig = AppConfig { appConfigSetting1 :: Int , appConfigSetting2 :: Bool , appConfigSetting3 :: String }) deriving (Generic, Show, DefaultSource)> deriving (ConfigSource, ConfigParser) via (Config AppConfig):} pPrint $ configSource @AppConfigFree ( fromList [! ( "appConfigSetting1" , Free ( fromList [] ) ) ,! ( "appConfigSetting2" , Free ( fromList [] ) ) ,! ( "appConfigSetting3" , Free ( fromList [] ) ) ] )cfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfgcfg   Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>Z'(&%" $#!  Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>bcfgThis function takes a separator and a list of keys and joins them from the end of the list to the beginning, interspersed with the provided separator.getEnvKey "_" ["A", "B", "C"]"A_B_C"cfgFolds a * from leaf to root, into distinct key paths. This is necessary for the way that hierarchical structures are represented in environment variables (i.e. "KEYA_SUBKEYA", "KEYA_SUBKEYB").Here is a visual representation of how the keys would get folded ! A / \ B C [ [ A, B ] , [ A, C ] ] import KeyTreeimport Data.Map qualified as MgetKeys $ Free $ M.singleton "A" $ Free (M.fromList [("B", Free M.empty), ("C", Free M.empty)])[["A","B"],["A","C"]]cfgGets all the keys from a configuration tree, and flattens the hierarchy so that each key is prefixed with its path through the tree.2Accepts separator to individuate the key prefixes.import KeyTreeimport Data.Map qualified as MshowEnvKeys' "-" $ Free $ M.singleton "A" $ Free (M.fromList [("B", Free M.empty), ("C", Free M.empty)]) ["A-B","A-C"]cfgSame as  but the  is generated via a "import GHC.Generics (Generic (..))$import Cfg.Source (ConfigSource(..))$import Cfg.Parser (ConfigParser(..))'import Cfg.Deriving.Config (Config(..))-import Cfg.Source.Default (DefaultSource(..)):{&data Sub = Sub { c :: Int, d :: Bool }) deriving (Generic, Show, DefaultSource)6 deriving (ConfigSource, ConfigParser) via Config Sub#data TypeCon = DataCon { a :: Sub }) deriving (Generic, Show, DefaultSource): deriving (ConfigSource, ConfigParser) via Config TypeCon:}showEnvKeys @TypeCon "_" ["a_c","a_d"]cfg Separatorcfg List of keyscfg SeparatorcfgConfiguration tree Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone("%&')*-/01369<>cucfgcfg Jonathan Lorimer, 2023MITjonathanlorimer@pm.mestableNone'"%&')*-/01369<>ncfgThis function folds the tree from root to leaf accumulating the keys along the way. At the leaf we lookup the aggregated key in the environment, if there is a default then we use that for missing keys.If you are looking at the source code this is what the functions in the where clause do:valF: Gets called on  values in the original tree passed in, these indicate defaulted values, so we use the default if looking the value up in the environment failed.accF: This operates on the accumulated key, and is responsible for looking up the value in the environment when we hit the  Free M.empty case.stepF: This is the step function for the fold and accumulates the keys as we traverse down the tree.mkKey: This function is the same as  + except that it uses  flip mappend. The reason for this is that we insert keys into the accumulator as we traverse down so they end up in reversed order, then we foldr over them so we just need to make sure that we are placing the elements at the end of the list on the left hand side of the aggregate key.cfgThis function is the same as + but with the separator specialized to "_".import System.Environmentimport Data.Map qualified as MsetEnv "A_B" "Functor"setEnv "A_C" "Applicative"setEnv "A_D" "Monad"envSource $ Free $ M.fromList [("A", Free $ M.fromList [("B", Free M.empty), ("C", Free M.empty), ("D", Free M.empty)])]Free (fromList [("A",Free (fromList [("B",Pure "Functor"),("C",Pure "Applicative"),("D",Pure "Monad")]))])cfgThis function can be used to print a dotenv style file with all the aggregate keys, none of the values will be filled in.Useful for testing what your expected environment variables should look like, and generating an env var file template.cfgRequires a type annotation for your configuration type (with a  and E instance), and a separator, and will go out and fetch the values from environment variables then return your type parsed from those values. getEnvConfigSep @AppConfig "_"cfg The same as ) but with the separator hard coded to "_"cfg The same as  but with the separator hard coded to "_" and it uses a type application to generate the configuration source tree representation. printDotEnv @AppConfig ".env"cfg SeparatorcfgConfiguration sourcecfg(Configuration tree with values filled incfgDestination filepathcfg SeparatorcfgSource representationcfg Separator,-./0./1./023456789###:#;'%&$$$<=>?@)ABCDEFGHIJ(KLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~! " " "                                                                    +   cfg-0.0.2.2-inplaceKeyTreeCfg.Deriving.Assert Cfg.OptionsCfg.Deriving.KeyModifierCfg.Source.Default Cfg.ParserCfg.Parser.ValueCfg.Parser.ConfigCfg.Deriving.Value Cfg.SourceCfg.Source.ConfigCfg.Deriving.Config Cfg.Env.KeysCfgCfg.Envcfg Data.Text stripPrefix Data.ChartoUppertoLowerText $dmdefaultsData.Map foldrWithKeyMap$dmparseConfig ValueParser Cfg.DerivingConfig ConfigParser ConfigRoot gParseConfigValue RootOptions KeyOptionsConstructorNameTypeNameRootKeyIdentity KeyModifier Cfg.KeyTree getEnvKeycontainers-0.6.8-inplaceData.Map.Internalfree-5.2-HYM0gD1Fq69B83fsZa2Ny8Control.Monad.FreeFreePureAssertTopLevelRecordIsTopLevelRecordAssert$fAssertFalsemsg$fAssertTruemsg ConfigOptionsRootKeyrootOptionsModifierrootOptionsRootKeykeyOptionsModifierdefaultKeyOptionsdefaultRootOptionsdefaultConfigOptions keyModifiergetKeyModifier CamelToKebab CamelToSnakeCamelTo StripSuffix StripPrefix UpperFirst LowerFirstToUpperToLowermapFirstcamelTo camelToText$fKeyModifierTYPECamelTo$fKeyModifierTYPEStripSuffix$fKeyModifierTYPEStripPrefix$fKeyModifierTYPEUpperFirst$fKeyModifierTYPELowerFirst$fKeyModifierTYPEToUpper$fKeyModifierTYPEToLower$fKeyModifierTYPETuple4$fKeyModifierTYPETuple3$fKeyModifierTYPETuple2$fKeyModifierList:$fKeyModifierList[]$fKeyModifierUnit()$fKeyModifierTYPEIdentity#$fKeyModifierRootKeyConstructorName$fKeyModifierRootKeyTypeName DefaultSourcedefaults KeyForest foldKeyTree appendFold mayAppendFoldappendTraversemayAppendTraverseparser parseConfigConfigParseError MissingKeyExpectedKeyFoundValueExpectedValueFoundForestValueParseErrorParser$fValueParserTuple2$fValueParserWord64$fValueParserWord32$fValueParserWord16$fValueParserWord8$fValueParserWord$fValueParserInteger$fValueParserInt64$fValueParserInt32$fValueParserInt16$fValueParserInt8$fValueParserInt$fValueParserFloat$fValueParserDouble$fValueParserNonEmpty$fValueParserList$fValueParserText$fValueParserByteString$fValueParserByteString0$fValueParserText0$fValueParserChar$fValueParserBool$fValueParserUnit$fConfigParserTuple2$fConfigParserWord64$fConfigParserWord32$fConfigParserWord16$fConfigParserWord8$fConfigParserWord$fConfigParserInteger$fConfigParserInt64$fConfigParserInt32$fConfigParserInt16$fConfigParserInt8$fConfigParserInt$fConfigParserFloat$fConfigParserDouble$fConfigParserMaybe$fConfigParserNonEmpty$fConfigParserList$fConfigParserText$fConfigParserByteString$fConfigParserByteString0$fConfigParserText0$fConfigParserChar$fConfigParserBool$fConfigParserUnit$fEqConfigParseError$fShowConfigParseError$fGenericConfigParseError GValueParsergParserdefaultValueParser$fGValueParser:*:$fGValueParser:+:$fGValueParserM1$fGValueParserM10$fGValueParserM11$fGValueParserK1$fGValueParserU1$fGValueParserV1 GConfigParserdefaultParseConfig$fGConfigParser:*:$fGConfigParserM1$fGConfigParserM10$fGConfigParserM11$fGConfigParserK1unValue$fConfigParserValue$fValueParserValue$fGenericValue ConfigSource configSource FetchSource$fConfigSourceTYPEValue$fConfigSourceTYPETuple2$fConfigSourceTYPEWord64$fConfigSourceTYPEWord32$fConfigSourceTYPEWord16$fConfigSourceTYPEWord8$fConfigSourceTYPEWord$fConfigSourceTYPEInteger$fConfigSourceTYPEInt64$fConfigSourceTYPEInt32$fConfigSourceTYPEInt16$fConfigSourceTYPEInt8$fConfigSourceTYPEInt$fConfigSourceTYPEFloat$fConfigSourceTYPEDouble$fConfigSourceTYPEMaybe$fConfigSourceTYPEVector$fConfigSourceTYPENonEmpty$fConfigSourceTYPEList$fConfigSourceTYPEText$fConfigSourceTYPEByteString$fConfigSourceTYPEByteString0$fConfigSourceTYPEText0$fConfigSourceTYPEChar$fConfigSourceTYPEBool$fConfigSourceTYPEUnit GConfigSource gConfigSourcedefaultConfigSource$fGConfigSource:+:$fGConfigSource:*:$fGConfigSourceM1$fGConfigSourceM10$fGConfigSourceM11$fGConfigSourceK1ConfigRootOptionsconfigRootOptionsGetConfigOptions getOptions unConfigRoot ConfigOptsunConfigOptionsunConfig$fConfigParserConfig$fConfigSourceTYPEConfig$fGenericConfig$fGenericConfigOpts$fGenericConfigRoot$fConfigParserConfigOpts$fConfigSourceTYPEConfigOpts$fGetConfigOptionskt$fConfigParserConfigRoot$fConfigSourceTYPEConfigRoot+$fConfigRootOptionsRootKeykConstructorNamef$$fConfigRootOptionsRootKeykTypeNamefgetKeys showEnvKeys' showEnvKeys getConfigRaw getConfig$fDefaultSourceTYPEAppConfig5$fGenericAppConfig5$fShowAppConfig5$fConfigSourceTYPEAppConfig5$fConfigParserAppConfig5$fGenericAppConfig4$fShowAppConfig4$fDefaultSourceTYPEAppConfig4$fConfigSourceTYPEAppConfig4$fConfigParserAppConfig4$fGenericAppConfig3$fShowAppConfig3$fDefaultSourceTYPEAppConfig3$fConfigSourceTYPEAppConfig3$fConfigParserAppConfig3$fGenericRedisConfig3$fShowRedisConfig3$fDefaultSourceTYPERedisConfig3$fConfigSourceTYPERedisConfig3$fConfigParserRedisConfig3$fGenericWarpConfig3$fShowWarpConfig3$fDefaultSourceTYPEWarpConfig3$fConfigSourceTYPEWarpConfig3$fConfigParserWarpConfig3$fGenericAppConfig2$fShowAppConfig2$fDefaultSourceTYPEAppConfig2$fConfigSourceTYPEAppConfig2$fConfigParserAppConfig2$fGenericRedisConfig2$fShowRedisConfig2$fDefaultSourceTYPERedisConfig2$fConfigSourceTYPERedisConfig2$fConfigParserRedisConfig2$fGenericWarpConfig2$fShowWarpConfig2$fDefaultSourceTYPEWarpConfig2$fConfigSourceTYPEWarpConfig2$fConfigParserWarpConfig2$fGenericAppConfig$fShowAppConfig$fDefaultSourceTYPEAppConfig$fConfigSourceTYPEAppConfig$fConfigParserAppConfig$fGenericRedisConfig$fShowRedisConfig$fDefaultSourceTYPERedisConfig$fConfigSourceTYPERedisConfig$fConfigParserRedisConfig$fGenericWarpConfig$fShowWarpConfig$fDefaultSourceTYPEWarpConfig$fConfigSourceTYPEWarpConfig$fConfigParserWarpConfig$fGenericEnvironment$fShowEnvironment$fDefaultSourceTYPEEnvironment$fConfigSourceTYPEEnvironment$fValueParserEnvironment$fConfigParserEnvironment envSourceSep envSource printDotEnv'getEnvConfigSep getEnvConfig printDotEnvbaseGHC.Baseid GHC.MaybeMaybe ApplicativeData.Traversable sequenceA Traversableghc-prim GHC.TypesIOsprdplusminusnumberdecimalintegral fractional GHC.GenericsK1