settei
Safe HaskellNone
LanguageGHC2024

Settei.Config

Description

A Config describes configuration effects without reading a source. Independent settings compose with Applicative; runtime-dependent effects compose with Control.Selective. The latter preserves a static over-approximation while allowing an interpreter to skip an unused branch.

For example, a caller can declare a production-only password (assuming environmentSetting :: Setting Text and passwordSetting :: Setting Text):

productionPassword :: Config (Maybe Text)
productionPassword =
  whenEq (required environmentSetting) "production" (required passwordSetting)

Inspection needs no environment variables or files:

fmap (renderKey . schemaSettingKey) (schemaNecessary (describe productionPassword))
-- ["runtime.environment"]

For arbitrary selective branch shapes, use select directly; the production-only declaration above desugars to:

select
  ((environment -> if environment == "production" then Left () else Right Nothing)
    <$> required environmentSetting)
  ((password _ -> Just password) <$> required passwordSetting)

Config intentionally has no Monad instance. Monadic binding could construct new keys from resolved values and would make complete static inspection impossible.

Synopsis

Documentation

data Config a Source #

The private, typed syntax tree behind the public declaration language.

Instances

Instances details
Applicative Config Source # 
Instance details

Defined in Settei.Internal.Config

Methods

pure :: a -> Config a #

(<*>) :: Config (a -> b) -> Config a -> Config b #

liftA2 :: (a -> b -> c) -> Config a -> Config b -> Config c #

(*>) :: Config a -> Config b -> Config b #

(<*) :: Config a -> Config b -> Config a #

Functor Config Source # 
Instance details

Defined in Settei.Internal.Config

Methods

fmap :: (a -> b) -> Config a -> Config b #

(<$) :: a -> Config b -> Config a #

Selective Config Source # 
Instance details

Defined in Settei.Internal.Config

Methods

select :: Config (Either a b) -> Config (a -> b) -> Config b #

describe :: Config a -> Schema Source #

Inspect every possible request without reading configuration sources.

fallbackTo :: Config (Maybe a) -> Config a -> Config a Source #

Use the first declaration's value when present; otherwise evaluate the fallback.

This is the key-migration idiom: optional newSetting fallbackTo required oldSetting reads a renamed key and consults the old key only when no source supplies the new one.

Desugars to select. Schema footprint: the primary declaration's settings keep their presence; the fallback's settings become conditional; one Condition row records the primary's possible keys as dependencies and the fallback's possible keys as activated settings. The alias is declaration-level, not per-source: a value for the primary key in any source, however low its precedence, suppresses the fallback entirely.

optional :: Setting a -> Config (Maybe a) Source #

Request a setting without failing when no source supplies it.

required :: Setting a -> Config a Source #

Require one setting when this declaration path is evaluated.

whenConfig :: Config Bool -> Config a -> Config (Maybe a) Source #

Evaluate a declaration only when a condition is True.

Desugars to select; no new syntax is introduced. Schema footprint: every setting inside the condition keeps its presence (a required condition setting stays necessary); every setting inside the branch becomes conditional; one Condition row is recorded whose dependencies are the condition's possible keys and whose activated settings are the branch's possible keys. At resolution time a False condition reports the branch's settings as not selected rather than missing.

whenEq :: Eq d => Config d -> d -> Config a -> Config (Maybe a) Source #

Evaluate a declaration only when a scrutinee equals an expected value.

whenEq (required environmentSetting) Production (required passwordSetting) requires the password only when the resolved environment is Production. Schema footprint is identical to whenConfig: scrutinee settings keep their presence, branch settings become conditional, and one Condition row links them.

withDefault :: Setting a -> Default a -> Config a Source #

Request a setting, evaluating its named fallback only when no source supplies it.