Safe Haskell | None |
---|---|
Language | Haskell2010 |
Synopsis
- option :: OptReader a -> (OptionOpt '[] a -> OptionOpt attr b) -> Opt b
- flag :: a -> a -> (FlagOpt '[] a -> FlagOpt attr b) -> Opt b
- switch :: (FlagOpt '[] Bool -> FlagOpt attr Bool) -> Opt Bool
- switch' :: (FlagOpt '[] Bool -> FlagOpt attr Bool) -> Opt Bool
- argument :: OptReader a -> (ArgumentOpt '[] a -> ArgumentOpt attr b) -> Opt b
- newtype Single (a :: Type) (f :: Type -> Type) = Single {
- getSingle :: f a
- single :: f a -> Single a f
- fromSingle :: Single a Identity -> a
- newtype Nested (b :: Type) (f :: Type -> Type) = Nested (HKD b f)
- nested :: forall b f k. (Build b f k, Coercible (HKD b f) (Nested b f), Coercible k (Nest k f)) => Nest k f
- getNested :: Construct f b => Nested b f -> f b
- fromNested :: Construct Identity b => Nested b Identity -> b
- data AssocListF (ts :: [Symbol]) (xs :: [(Type -> Type) -> Type]) (f :: Type -> Type) where
- ANil :: AssocListF '[] '[] f
- ACons :: x f -> AssocListF ts xs f -> AssocListF (t ': ts) (x ': xs) f
- type family l :+ r = (res :: (Type -> Type) -> Type) where ...
- pattern (:+) :: x f -> AssocListF ts xs f -> AssocListF (t ': ts) (x ': xs) f
- data (t :: Symbol) :-> (v :: (Type -> Type) -> Type) :: (Type -> Type) -> Type
- data ((a :: (Type -> Type) -> Type) :* (b :: (Type -> Type) -> Type)) (f :: Type -> Type) = (a f) :* (b f)
- newtype Tagged (t :: k) (a :: (Type -> Type) -> Type) (f :: Type -> Type) = Tagged {
- unTagged :: a f
- long :: HasLong o attr => String -> o attr a -> o attr a
- short :: HasShort o attr => Char -> o attr a -> o attr a
- help :: HasHelp o attr => String -> o attr a -> o attr a
- metavar :: HasMetavar o attr => String -> o attr a -> o attr a
- envVar :: HasEnvVar o attr => String -> o attr a -> o attr a
- defaultVal :: (HasDefaultVal o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "defaultVal" '["defaultStr", "required"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "defaultVal" "optional")) => a -> o attr a -> o (OptDefault ': attr) a
- defaultStr :: (HasDefaultStr o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "defaultStr" '["defaultVal", "required"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "defaultStr" "optional")) => String -> o attr a -> o (OptDefault ': attr) a
- required :: (HasRequired o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "required" '["defaultVal", "defaultStr"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "required" "optional")) => o attr a -> o (OptDefault ': attr) a
- optional :: (HasOptional o attr, NotInAttrs OptOptional attr (DuplicateAttrErr "optional"), NotInAttrs OptDefault attr (IncompatibleAttrsErr "optional" "defaultVal")) => o attr a -> o (OptOptional ': attr) (Maybe a)
- toOpt :: IsOpt o attr => o attr a -> Opt a
- data Opt a
- parseWith :: (String -> Maybe a) -> String -> Either String a
- readParser :: Read a => OptReader a
- strParser :: IsString s => String -> Either String s
- boolParser :: String -> Either String Bool
- manyParser :: String -> OptReader a -> OptReader [a]
- execOpt :: forall c a. (TraversableB a, ProductB a, TraversableB c, ProductB c, GetSource c Identity, RunSource (SourceVal c) a) => c Opt -> a Opt -> IO (a Identity)
- execOptDef :: forall a. (TraversableB a, ProductB a) => a Opt -> IO (a Identity)
- execCommands :: forall c ts xs. (TraversableB (VariantF xs), TraversableB c, ProductB c, Subcommands ts xs, GetSource c Identity, All (RunSource (SourceVal (c :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) => c Opt -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
- execCommandsDef :: forall ts xs. (TraversableB (VariantF xs), Subcommands ts xs, All (RunSource (SourceVal (DefaultSources :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) => AssocListF ts xs Opt -> IO (VariantF xs Identity)
- data EnvSource (f :: Type -> Type) = EnvSource
- newtype JSONSource f = JSONSource (f ConfigFile)
- newtype YAMLSource f = YAMLSource (f ConfigFile)
- data ConfigFile
- noSources :: NoSource f
- defaultSources :: DefaultSources f
- getCtx :: IO HargCtx
- ctxFromArgs :: Args -> IO HargCtx
- ctxFromEnv :: Environment -> IO HargCtx
- pureCtx :: Environment -> Args -> HargCtx
- data VariantF (xs :: [(Type -> Type) -> Type]) (f :: Type -> Type) where
- fromVariantF :: FromVariantF xs result f => VariantF xs f -> FoldSignatureF xs result f
- pattern In1 :: x1 f -> VariantF (x1 ': xs) f
- pattern In2 :: x2 f -> VariantF (x1 ': (x2 ': xs)) f
- pattern In3 :: x3 f -> VariantF (x1 ': (x2 ': (x3 ': xs))) f
- pattern In4 :: x4 f -> VariantF (x1 ': (x2 ': (x3 ': (x4 ': xs)))) f
- pattern In5 :: x5 f -> VariantF (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': xs))))) f
- class FunctorB (b :: (k -> Type) -> Type)
- class FunctorB b => TraversableB (b :: (k -> Type) -> Type)
- class FunctorB b => ProductB (b :: (k -> Type) -> Type)
- newtype Rec p a (x :: k) :: forall k. Type -> Type -> k -> Type = Rec {}
- data HKD structure (f :: Type -> Type)
- class Build structure (f :: Type -> Type) k | f structure -> k
- build :: Build structure f k => k
- class Construct (f :: Type -> Type) structure
- construct :: Construct f structure => HKD structure f -> f structure
Summary
harg
is a wrapper around optparse-applicative
that allows blending
command-line configuration with environment variables, defaults as well as
other sources such as JSON or YAML files. Here are some very simple examples:
- Flat configuration type
data Config
= Config
{ host :: String
, port :: Int
, log :: Bool
, dir :: Maybe String
}
-- Using HKD
from higgledy
configOpt :: HKD Config Opt
configOpt
= build @Config hostOpt portOpt logOpt dirOpt
where
hostOpt
= optionWith strParser
( long "host"
. short 'h'
. help "Hostname"
. envVar "HOST_NAME"
)
portOpt
= optionWith readParser
( long "port"
. short 'p'
. help "Port number"
. defaultVal 5432
)
logOpt
= switchWith
( long "log"
. help "Whether to log or not"
)
dirOpt
= argumentWith strParser
( help "Some directory"
. envVar "SOME_DIR"
. optional
)
main :: IO Config
main = do
result <- execOpt defaultSources configOpt
pure $ runIdentity (construct result)
The above could also be:
type ConfigOpt = Single String :* Single Int :* Single Bool :* Single String configOpt :: ConfigOpt Opt configOpt = hostOpt :* portOpt :* logOpt :* dirOpt where ... main :: IO Config main = do host :* port :* log :* dir <- execOpt defaultSources configOpt pure $ runIdentity $ Config <$> getSingle host <*> getSingle port <*> getSingle log <*> getSingle dir
- Nested configuration type
data Config
= Config
{ dbConfig :: DbConfig
, serverConfig :: ServerConfig
}
data DbConfig
= DbConfig
{ dbHost :: String
, dbPort :: Int
}
data ServerConfig
= ServerConfig
{ srvPort :: Int
, srvLog :: Bool
}
type ConfigOpt
= HKD DbConfig
:* HKD ServerConfig
configOpt :: ConfigOpt Opt
configOpt
= dbOpt :* srvOpt
where
dbOpt = build DbConfig ...
srvOpt = build
ServerConfig ...
main :: IO Config
main = do
db :* srv <- execOpt defaultSources configOpt
pure
$ runIdentity
$ Config
<$> construct db
<*> construct srv
- Subparsers
data OneConfig = OneConfig ... data OtherConfig = OtherConfig ... data Config = "one" :-> OneConfig :+ "other" :-> OtherConfig configOpt :: Config Opt configOpt = oneOpt :+ otherOpt :+ ANil where oneOpt = ... otherOpt = ... main :: IO () main = do result <- execOpt defaultSources configOpt case result of HereF one -> runWithOne one ThereF (HereF other) -> runWithOther other where runWithOne :: One -> IO () runWithOne = ... runWithOther :: Other -> IO () runWithOther = ...
TODO: more (and better) examples
Option declaration
Create a flag parser, equivalent to option
. The
first argument is the default value (returned when the flag modifier is
absent), and the second is the active value (returned when the flag
modifier is present). The second argument is the modifiers to add to the
option, and can be defined by using function composition (.
).
someFlag :: Opt Int someFlag = flag 0 1 ( long "someflag" . help "Some flag" )
switch :: (FlagOpt '[] Bool -> FlagOpt attr Bool) -> Opt Bool Source #
A flag
parser, specialized to Bool
. The parser (e.g. when parsing
an environment variable) will accept true
and false
, but case
insensitive, rather than using the Read
instance for Bool
. The
default value is False
, and the active value is True
.
someSwitch :: Opt Bool someSwitch = switch ( long "someswitch" . help "Some switch" )
argument :: OptReader a -> (ArgumentOpt '[] a -> ArgumentOpt attr b) -> Opt b Source #
newtype Single (a :: Type) (f :: Type -> Type) Source #
Single a f
is a newtype around f a
, which allows mixing non-nested
with nested values when creating configuration parsers, using
:*
.
data User = User { name :: String, age :: Int } deriving Generic myConfig :: (Nested User :* Single Int) Opt myConfig = nested @User nameOpt ageOpt :* single intOpt where ...
Instances
ProductB (Single a :: (Type -> Type) -> Type) Source # | |
TraversableB (Single a :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Single btraverse :: Applicative t => (forall (a0 :: k). f a0 -> t (g a0)) -> Single a f -> t (Single a g) # | |
FunctorB (Single a :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Single | |
(Show a, Show (f a)) => Show (Single a f) Source # | |
Generic (f a) => Generic (Single a f) Source # | |
FromJSON (f a) => FromJSON (Single a f) Source # | |
type Rep (Single a f) Source # | |
Defined in Options.Harg.Single |
fromSingle :: Single a Identity -> a Source #
Helper for when f ~ Identity
newtype Nested (b :: Type) (f :: Type -> Type) Source #
Newtype wrapper around HKD
.
Instances
ProductB (HKD b) => ProductB (Nested b :: (Type -> Type) -> Type) Source # | |
TraversableB (HKD b) => TraversableB (Nested b :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Nested btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> Nested b f -> t (Nested b g) # | |
FunctorB (HKD b) => FunctorB (Nested b :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Nested | |
Generic (HKD b f) => Generic (Nested b f) Source # | |
FromJSON (HKD b f) => FromJSON (Nested b f) Source # | |
type Rep (Nested b f) Source # | |
Defined in Options.Harg.Nested |
nested :: forall b f k. (Build b f k, Coercible (HKD b f) (Nested b f), Coercible k (Nest k f)) => Nest k f Source #
data AssocListF (ts :: [Symbol]) (xs :: [(Type -> Type) -> Type]) (f :: Type -> Type) where Source #
A heterogeneous list that holds higher-kinded types and the associated
type constructor, along with a type level list of Symbol
s that act
as tags for each type.
ANil :: AssocListF '[] '[] f | |
ACons :: x f -> AssocListF ts xs f -> AssocListF (t ': ts) (x ': xs) f |
type family l :+ r = (res :: (Type -> Type) -> Type) where ... infixr 4 Source #
Helper type-level function to construct an AssocList
which is not
yet applied to the type constructor that needs to be fully applied.
type Config = "run" :-> RunConfig :+ "test" :-> TestConfig
Config
above has type (Type -> Type) -> Type
, and requires a type
like Opt
to be fully applied.
(tl :-> vl) :+ (tr :-> vr) = AssocListF '[tl, tr] '[vl, vr] | |
(tl :-> vl) :+ (AssocListF ts vs) = AssocListF (tl ': ts) (vl ': vs) | |
l :+ r = TypeError (((Text "Invalid type for tagged options. Construct like this:" :$$: Text "type MyConfig") :$$: Text " = \"one\" :-> ConfigForOne") :$$: Text " :+ \"two\" :-> ConfigForTwo") |
pattern (:+) :: x f -> AssocListF ts xs f -> AssocListF (t ': ts) (x ': xs) f infixr 4 Source #
data ((a :: (Type -> Type) -> Type) :* (b :: (Type -> Type) -> Type)) (f :: Type -> Type) infixr 4 Source #
Infix version of Product
. Allows to combine
higher-kinded types, and keep them partially applied until needed:
data User = User { name :: String, age :: Int } deriving Generic type Config = Nested User :* Single Int configOpt :: Config Opt configOpt = ...
(a f) :* (b f) infixr 4 |
Instances
newtype Tagged (t :: k) (a :: (Type -> Type) -> Type) (f :: Type -> Type) Source #
This type adds a type-level phantom tag to a higher-kinded type.
Its JSON instance allows using :*
with JSONSource
.
Instances
ProductB a => ProductB (Tagged t a :: (Type -> Type) -> Type) Source # | |
TraversableB a => TraversableB (Tagged t a :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Het.Prod btraverse :: Applicative t0 => (forall (a0 :: k). f a0 -> t0 (g a0)) -> Tagged t a f -> t0 (Tagged t a g) # | |
FunctorB a => FunctorB (Tagged t a :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Het.Prod | |
(FromJSON (a Maybe), FromJSON (b Maybe), ProductB a, ProductB b, KnownSymbol ta, KnownSymbol tb) => FromJSON ((Tagged ta a :* Tagged tb b) Maybe) Source # | |
(FromJSON (a Maybe), FromJSON (b' Maybe), ProductB a, ProductB b', KnownSymbol ta, b' ~ (Tagged tb b :* c)) => FromJSON ((Tagged ta a :* (Tagged tb b :* c)) Maybe) Source # | |
Generic (Tagged t a f) Source # | |
FromJSON (a f) => FromJSON (Tagged t a f) Source # | |
type Rep (Tagged t a f) Source # | |
Defined in Options.Harg.Het.Prod |
Option modifiers
metavar :: HasMetavar o attr => String -> o attr a -> o attr a Source #
Add a metavar
metavar to an option, to be
displayed as the meta-parameter next to long/short modifiers
envVar :: HasEnvVar o attr => String -> o attr a -> o attr a Source #
Specify an environment variable to lookup for an option
defaultVal :: (HasDefaultVal o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "defaultVal" '["defaultStr", "required"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "defaultVal" "optional")) => a -> o attr a -> o (OptDefault ': attr) a Source #
Add a default value to an option. Cannot be used in conjuction with
with required
, defaultStr
or optional
.
defaultStr :: (HasDefaultStr o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "defaultStr" '["defaultVal", "required"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "defaultStr" "optional")) => String -> o attr a -> o (OptDefault ': attr) a Source #
Add a default unparsed value to an option. Cannot be used in conjuction
with defaultVal
, required
or optional
.
required :: (HasRequired o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "required" '["defaultVal", "defaultStr"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "required" "optional")) => o attr a -> o (OptDefault ': attr) a Source #
Mark an option as required. Cannot be used in conjunction with
optional
, defaultVal
or requiredStr
.
optional :: (HasOptional o attr, NotInAttrs OptOptional attr (DuplicateAttrErr "optional"), NotInAttrs OptDefault attr (IncompatibleAttrsErr "optional" "defaultVal")) => o attr a -> o (OptOptional ': attr) (Maybe a) Source #
Specify that an option is optional. This will convert an Opt a
to an
Opt (Maybe a)
. Cannot be used in conjunction with defaultVal
, defaultStr
or required
.
The basic option type
Option parsers
readParser :: Read a => OptReader a Source #
A parser that uses the Read
instance to parse into a type.
strParser :: IsString s => String -> Either String s Source #
A parser that returns a string. Any type that has an instance of
IsString
will work, and this parser always succeeds.
boolParser :: String -> Either String Bool Source #
A parser that returns a Bool
. This will succeed for the strings
true
and false
in a case-insensitive manner.
A parser that can parse many items, returning a list.
Executing options
:: (TraversableB a, ProductB a, TraversableB c, ProductB c, GetSource c Identity, RunSource (SourceVal c) a) | |
=> c Opt | Source options |
-> a Opt | Target configuration options |
-> IO (a Identity) |
Run the option parser and combine with values from the specified sources
:: (TraversableB a, ProductB a) | |
=> a Opt | Target configuration options |
-> IO (a Identity) |
Run the option parser only with default sources (environment variables)
:: (TraversableB (VariantF xs), TraversableB c, ProductB c, Subcommands ts xs, GetSource c Identity, All (RunSource (SourceVal (c :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) | |
=> c Opt | Source options |
-> AssocListF ts xs Opt | Target options associated with subcommands |
-> IO (VariantF xs Identity) |
Run the subcommand parser and combine with values from the specified sources
:: (TraversableB (VariantF xs), Subcommands ts xs, All (RunSource (SourceVal (DefaultSources :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) | |
=> AssocListF ts xs Opt | Target options associated with subcommands |
-> IO (VariantF xs Identity) |
Run the subcommand parser only with default sources (environment variables)
Option sources
data EnvSource (f :: Type -> Type) Source #
Source that enables a parser to read options from environment variables.
Instances
GetSource EnvSource f Source # | |
Generic (EnvSource f) Source # | |
ProductB EnvSource Source # | |
TraversableB EnvSource Source # | |
Defined in Options.Harg.Sources.Env btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> EnvSource f -> t (EnvSource g) # | |
FunctorB EnvSource Source # | |
Defined in Options.Harg.Sources.Env | |
type SourceVal EnvSource Source # | |
Defined in Options.Harg.Sources.Env | |
type Rep (EnvSource f) Source # | |
newtype JSONSource f Source #
Source that enables a parser to read options from a JSON file.
JSONSource (f ConfigFile) |
Instances
newtype YAMLSource f Source #
Source that enables a parser to read options from a YAML file.
YAMLSource (f ConfigFile) |
Instances
data ConfigFile Source #
This type describes configuration files, for use with e.g. the JSON
source. The reason to not use FilePath
directly is that the user might
prefer to do nothing if the option for the config file has not been not
provided, and there's no default. Because this type has an IsString
instance, it's very easy to define an option. For example, to define a json
source with a default value:
srcOpt :: JSONSource Opt srcOpt = JSONSource jsonOpt where jsonOpt = optionWith strParser ( long "json-config" . defaultVal (ConfigFile "~/config.json") )
And an optional JSON source:
srcOpt :: JSONSource Opt srcOpt = JSONSource jsonOpt where jsonOpt = optionWith strParser ( long "json-config" . defaultVal NoConfigFile )
Instances
IsString ConfigFile Source # | |
Defined in Options.Harg.Sources.Types fromString :: String -> ConfigFile # |
defaultSources :: DefaultSources f Source #
Default sources, equivalent to EnvSource
Parser context
ctxFromEnv :: Environment -> IO HargCtx Source #
Variant
data VariantF (xs :: [(Type -> Type) -> Type]) (f :: Type -> Type) where Source #
A Variant is similar to nested Either
s. For example, Variant '[Int,
Bool, Char]
is isomorphic to Either Int (Either Bool Char)
. VariantF
is a variant for higher-kinded types, which means that the type-level list
holds types of kind (Type -> Type) -> Type
, and the second parameter is
the type constructor f :: Type -> Type
. To pattern match on a variant,
HereF
and ThereF
can be used:
getFromVariant :: Variant '[Int, Bool, String] -> Bool getFromVariant (ThereF (HereF b)) = b
Instances
(TraversableB x, TraversableB (VariantF xs)) => TraversableB (VariantF (x ': xs) :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Het.Variant btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> VariantF (x ': xs) f -> t (VariantF (x ': xs) g) # | |
TraversableB (VariantF ([] :: [(Type -> Type) -> Type])) Source # | |
Defined in Options.Harg.Het.Variant btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> VariantF [] f -> t (VariantF [] g) # | |
(FunctorB x, FunctorB (VariantF xs)) => FunctorB (VariantF (x ': xs) :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Het.Variant | |
FunctorB (VariantF ([] :: [(Type -> Type) -> Type])) Source # | |
Defined in Options.Harg.Het.Variant |
fromVariantF :: FromVariantF xs result f => VariantF xs f -> FoldSignatureF xs result f Source #
Re-exports
barbies
class FunctorB (b :: (k -> Type) -> Type) #
Barbie-types that can be mapped over. Instances of FunctorB
should
satisfy the following laws:
bmap
id
=id
bmap
f .bmap
g =bmap
(f . g)
There is a default bmap
implementation for Generic
types, so
instances can derived automatically.
Instances
class FunctorB b => TraversableB (b :: (k -> Type) -> Type) #
Barbie-types that can be traversed from left to right. Instances should satisfy the following laws:
t .btraverse
f =btraverse
(t . f) -- naturalitybtraverse
Identity
=Identity
-- identitybtraverse
(Compose
.fmap
g . f) =Compose
.fmap
(btraverse
g) .btraverse
f -- composition
There is a default btraverse
implementation for Generic
types, so
instances can derived automatically.
Instances
(FunctorB (HKD structure), GTraversableB (Rep structure)) => TraversableB (HKD structure :: (Type -> Type) -> Type) | |
Defined in Data.Generic.HKD.Types btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> HKD structure f -> t (HKD structure g) # | |
(TraversableB x, TraversableB (VariantF xs)) => TraversableB (VariantF (x ': xs) :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Het.Variant btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> VariantF (x ': xs) f -> t (VariantF (x ': xs) g) # | |
TraversableB (VariantF ([] :: [(Type -> Type) -> Type])) Source # | |
Defined in Options.Harg.Het.Variant btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> VariantF [] f -> t (VariantF [] g) # | |
TraversableB (HKD b) => TraversableB (Nested b :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Nested btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> Nested b f -> t (Nested b g) # | |
TraversableB (Single a :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Single btraverse :: Applicative t => (forall (a0 :: k). f a0 -> t (g a0)) -> Single a f -> t (Single a g) # | |
TraversableB (Proxy :: (k -> Type) -> Type) | |
Defined in Data.Barbie.Internal.Traversable btraverse :: Applicative t => (forall (a :: k0). f a -> t (g a)) -> Proxy f -> t (Proxy g) # | |
TraversableB (Void :: (k -> Type) -> Type) | |
Defined in Data.Barbie.Trivial btraverse :: Applicative t => (forall (a :: k0). f a -> t (g a)) -> Void f -> t (Void g) # | |
TraversableB (Unit :: (k -> Type) -> Type) | |
Defined in Data.Barbie.Trivial btraverse :: Applicative t => (forall (a :: k0). f a -> t (g a)) -> Unit f -> t (Unit g) # | |
TraversableB (Const a :: (k -> Type) -> Type) | |
Defined in Data.Barbie.Internal.Traversable btraverse :: Applicative t => (forall (a0 :: k0). f a0 -> t (g a0)) -> Const a f -> t (Const a g) # | |
TraversableB b => TraversableB (Barbie b :: (k -> Type) -> Type) | |
Defined in Data.Barbie.Internal.Instances btraverse :: Applicative t => (forall (a :: k0). f a -> t (g a)) -> Barbie b f -> t (Barbie b g) # | |
TraversableB a => TraversableB (Tagged t a :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Het.Prod btraverse :: Applicative t0 => (forall (a0 :: k). f a0 -> t0 (g a0)) -> Tagged t a f -> t0 (Tagged t a g) # | |
(TraversableB a, TraversableB b) => TraversableB (Sum a b :: (k -> Type) -> Type) | |
Defined in Data.Barbie.Internal.Traversable btraverse :: Applicative t => (forall (a0 :: k0). f a0 -> t (g a0)) -> Sum a b f -> t (Sum a b g) # | |
(TraversableB a, TraversableB b) => TraversableB (Product a b :: (k -> Type) -> Type) | |
Defined in Data.Barbie.Internal.Traversable btraverse :: Applicative t => (forall (a0 :: k0). f a0 -> t (g a0)) -> Product a b f -> t (Product a b g) # | |
(Traversable f, TraversableB b) => TraversableB (Compose f b :: (k -> Type) -> Type) | |
Defined in Data.Barbie.Internal.Traversable btraverse :: Applicative t => (forall (a :: k0). f0 a -> t (g a)) -> Compose f b f0 -> t (Compose f b g) # | |
TraversableB NoSource Source # | |
Defined in Options.Harg.Sources.NoSource btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> NoSource f -> t (NoSource g) # | |
TraversableB EnvSource Source # | |
Defined in Options.Harg.Sources.Env btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> EnvSource f -> t (EnvSource g) # | |
TraversableB DefaultStrSource Source # | |
Defined in Options.Harg.Sources.DefaultStr btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> DefaultStrSource f -> t (DefaultStrSource g) # | |
TraversableB YAMLSource Source # | |
Defined in Options.Harg.Sources.YAML btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> YAMLSource f -> t (YAMLSource g) # | |
TraversableB JSONSource Source # | |
Defined in Options.Harg.Sources.JSON btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> JSONSource f -> t (JSONSource g) # | |
(TraversableB a, TraversableB b) => TraversableB (a :* b :: (Type -> Type) -> Type) Source # | |
Defined in Options.Harg.Het.Prod btraverse :: Applicative t => (forall (a0 :: k). f a0 -> t (g a0)) -> (a :* b) f -> t ((a :* b) g) # |
class FunctorB b => ProductB (b :: (k -> Type) -> Type) #
Barbie-types that can form products, subject to the laws:
bmap
(\(Pair
a _) -> a) .uncurry
bprod
=fst
bmap
(\(Pair
_ b) -> b) .uncurry
bprod
=snd
Notice that because of the laws, having an internal product structure is not enough to have a lawful instance. E.g.
data Ok f = Ok {o1 :: fString
, o2 :: fInt
} data Bad f = Bad{b1 :: fString
, hiddenFromArg:Int
} -- no lawful instance
Intuitively, the laws for this class require that b
hides no structure
from its argument f
. Because of this, if we are given any:
x :: forall a . f a
then this determines a unique value of type b f
, witnessed by the buniq
method.
For example:
buniq
x = Ok {o1 = x, o2 = x}
Formally, buniq
should satisfy:
const
(buniq
x) =bmap
(const
x)
There is a default implementation of bprod
and buniq
for Generic
types,
so instances can derived automatically.
Instances
newtype Rec p a (x :: k) :: forall k. Type -> Type -> k -> Type #
Instances
(ConstraintsB b, AllB c b) => GConstraintsB (c :: k2 -> Constraint) (f :: k2 -> Type) (Rec (Self b (P0 (X :: k2 -> Type))) (b (X :: k2 -> Type)) :: Type -> Type) (Rec (b (P0 f)) (b f) :: k1 -> Type) (Rec (b (P0 (Product (Dict c) f))) (b (Product (Dict c) f)) :: k1 -> Type) | |
(SameOrParam b b', ConstraintsB b', AllB c b') => GConstraintsB (c :: k2 -> Constraint) (f :: k2 -> Type) (Rec (Other b (P0 (X :: k2 -> Type))) (b' (X :: k2 -> Type)) :: Type -> Type) (Rec (b (P0 f)) (b' f) :: k1 -> Type) (Rec (b (P0 (Product (Dict c) f))) (b' (Product (Dict c) f)) :: k1 -> Type) | |
GConstraintsB (c :: k2 -> Constraint) (f :: k2 -> Type) (Rec (P0 (X :: k2 -> Type) a) (X a) :: Type -> Type) (Rec (P0 f a) (f a) :: k1 -> Type) (Rec (P0 (Product (Dict c) f) a) (Product (Dict c) f a) :: k1 -> Type) | |
GConstraintsB (c :: k3 -> Constraint) (f :: k2 -> Type) (Rec a a :: Type -> Type) (Rec a a :: k1 -> Type) (Rec a a :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Constraints | |
GTraversableB (f :: k2 -> Type) (g :: k2 -> Type) (Rec (P0 f a) (f a) :: k1 -> Type) (Rec (P0 g a) (g a) :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Traversable gbtraverse :: Applicative t => (forall (a0 :: k). f a0 -> t (g a0)) -> Rec (P0 f a) (f a) x -> t (Rec (P0 g a) (g a) x) # | |
(SameOrParam b b', TraversableB b') => GTraversableB (f :: k2 -> Type) (g :: k2 -> Type) (Rec (b (P0 f)) (b' f) :: k1 -> Type) (Rec (b (P0 g)) (b' g) :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Traversable gbtraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> Rec (b (P0 f)) (b' f) x -> t (Rec (b (P0 g)) (b' g) x) # | |
(SameOrParam h h', SameOrParam b b', Traversable h', TraversableB b') => GTraversableB (f :: k2 -> Type) (g :: k2 -> Type) (Rec (h (b (P0 f))) (h' (b' f)) :: k1 -> Type) (Rec (h (b (P0 g))) (h' (b' g)) :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Traversable gbtraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> Rec (h (b (P0 f))) (h' (b' f)) x -> t (Rec (h (b (P0 g))) (h' (b' g)) x) # | |
GTraversableB (f :: k2 -> Type) (g :: k2 -> Type) (Rec a a :: k1 -> Type) (Rec a a :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Traversable gbtraverse :: Applicative t => (forall (a0 :: k). f a0 -> t (g a0)) -> Rec a a x -> t (Rec a a x) # | |
GFunctorB (f :: k2 -> Type) (g :: k2 -> Type) (Rec (P0 f a) (f a) :: k1 -> Type) (Rec (P0 g a) (g a) :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Functor | |
(SameOrParam b b', FunctorB b') => GFunctorB (f :: k2 -> Type) (g :: k2 -> Type) (Rec (b (P0 f)) (b' f) :: k1 -> Type) (Rec (b (P0 g)) (b' g) :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Functor | |
(SameOrParam h h', SameOrParam b b', Functor h', FunctorB b') => GFunctorB (f :: k2 -> Type) (g :: k2 -> Type) (Rec (h (b (P0 f))) (h' (b' f)) :: k1 -> Type) (Rec (h (b (P0 g))) (h' (b' g)) :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Functor | |
GFunctorB (f :: k2 -> Type) (g :: k2 -> Type) (Rec x x :: k1 -> Type) (Rec x x :: k1 -> Type) | |
Defined in Data.Barbie.Internal.Functor | |
GProductB (f :: k2 -> Type) (g :: k2 -> Type) (Rec (P0 f a) (f a) :: k1 -> Type) (Rec (P0 g a) (g a) :: k1 -> Type) (Rec (P0 (Product f g) a) (Product f g a) :: k1 -> Type) | |
(SameOrParam b b', ProductB b') => GProductB (f :: k2 -> Type) (g :: k2 -> Type) (Rec (b (P0 f)) (b' f) :: k1 -> Type) (Rec (b (P0 g)) (b' g) :: k1 -> Type) (Rec (b (P0 (Product f g))) (b' (Product f g)) :: k1 -> Type) | |
GProductBC (c :: k2 -> Constraint) (Rec (P0 (X :: k2 -> Type) a) (X a) :: Type -> Type) (Rec (P0 (Dict c) a) (Dict c a) :: k1 -> Type) | |
(ProductBC b, AllB c b) => GProductBC (c :: k2 -> Constraint) (Rec (Self b (P0 (X :: k2 -> Type))) (b (X :: k2 -> Type)) :: Type -> Type) (Rec (b (P0 (Dict c))) (b (Dict c)) :: k1 -> Type) | |
(SameOrParam b b', ProductBC b', AllB c b') => GProductBC (c :: k2 -> Constraint) (Rec (Other b (P0 (X :: k2 -> Type))) (b' (X :: k2 -> Type)) :: Type -> Type) (Rec (b (P0 (Dict c))) (b' (Dict c)) :: k1 -> Type) | |
GAllBC (Rec a a :: Type -> Type) | |
Defined in Data.Barbie.Internal.Constraints type GAllB c (Rec a a) :: Constraint # | |
GAllBC (Rec (Self b (P0 (X :: k -> Type))) (b (X :: k -> Type)) :: Type -> Type) | |
Defined in Data.Barbie.Internal.Constraints | |
(ConstraintsB b', SameOrParam b b') => GAllBC (Rec (Other b (P0 (X :: k -> Type))) (b' (X :: k -> Type)) :: Type -> Type) | |
Defined in Data.Barbie.Internal.Constraints | |
GAllBC (Rec (P0 (X :: k -> Type) a) (X a) :: Type -> Type) | |
Defined in Data.Barbie.Internal.Constraints | |
type GAllB (c :: k -> Constraint) (Rec a a :: Type -> Type) | |
Defined in Data.Barbie.Internal.Constraints | |
type GAllB (c :: k -> Constraint) (Rec (P0 (X :: k -> Type) a) (X a) :: Type -> Type) | |
Defined in Data.Barbie.Internal.Constraints | |
type GAllB (c :: k2 -> Constraint) (Rec (Self b (P0 (X :: k1 -> Type))) (b (X :: k1 -> Type)) :: Type -> Type) | |
type GAllB (c :: k -> Constraint) (Rec (Other b (P0 (X :: k -> Type))) (b' (X :: k -> Type)) :: Type -> Type) | |
higgledy
data HKD structure (f :: Type -> Type) #
Higher-kinded data (HKD) is the design pattern in which every field in our
type is wrapped in some functor f
:
data User f = User { name :: f String , age :: f Int }
Depending on the functor, we can get different behaviours: with Maybe
, we
get a partial structure; with Validation
, we get a piecemeal validator;
and so on. The HKD
newtype allows us to lift any type into an HKD-style
API via its generic representation.
>>>
:set -XDeriveGeneric -XTypeApplications
>>>
:{
data User = User { name :: String, age :: Int } deriving Generic :}
The HKD
type is indexed by our choice of functor and the structure we're
lifting. In other words, we can define a synonym for our behaviour:
>>>
import Data.Monoid (Last (..))
>>>
type Partial a = HKD a Last
... and then we're ready to go!
>>>
mempty @(Partial User)
User {name = Last {getLast = Nothing}, age = Last {getLast = Nothing}}
>>>
mempty @(HKD (Int, Bool) [])
(,) [] []
Instances
GBuild f structure ([] :: [Type]) (HKD structure f) | |
Defined in Data.Generic.HKD.Build | |
(ProductB (HKD structure), ConstraintsB (HKD structure), GProductBC (Rep structure)) => ProductBC (HKD structure :: (Type -> Type) -> Type) | |
(FunctorB (HKD structure), GConstraintsB (Rep structure), GAllBC (Rep structure)) => ConstraintsB (HKD structure :: (Type -> Type) -> Type) | |
(FunctorB (HKD structure), GProductB (Rep structure)) => ProductB (HKD structure :: (Type -> Type) -> Type) | |
(FunctorB (HKD structure), GTraversableB (Rep structure)) => TraversableB (HKD structure :: (Type -> Type) -> Type) | |
Defined in Data.Generic.HKD.Types btraverse :: Applicative t => (forall (a :: k). f a -> t (g a)) -> HKD structure f -> t (HKD structure g) # | |
GFunctorB (Rep structure) => FunctorB (HKD structure :: (Type -> Type) -> Type) | |
Defined in Data.Generic.HKD.Types | |
(Eq tuple, Generic xs, Tuple f xs tuple) => Eq (HKD xs f) | |
(Ord tuple, Generic xs, Tuple f xs tuple) => Ord (HKD xs f) | |
Defined in Data.Generic.HKD.Types | |
(Generic structure, GShow True (HKD_ f structure)) => Show (HKD structure f) | |
(Contravariant (HKD_ f structure), Functor (HKD_ f structure)) => Generic (HKD structure f) | |
(Semigroup tuple, Generic xs, Tuple f xs tuple) => Semigroup (HKD xs f) | |
(Monoid tuple, Generic xs, Tuple f xs tuple) => Monoid (HKD xs f) | |
(Generic structure, Function tuple, Tuple f structure tuple) => Function (HKD structure f) | |
(Arbitrary tuple, GToTuple (HKD_ f structure) tuple) => Arbitrary (HKD structure f) | |
(CoArbitrary tuple, GToTuple (HKD_ f structure) tuple) => CoArbitrary (HKD structure f) | |
Defined in Data.Generic.HKD.Types coarbitrary :: HKD structure f -> Gen b -> Gen b # | |
GFromJSON Zero (HKD_ f structure) => FromJSON (HKD structure f) Source # | |
type AllB (c :: Type -> Constraint) (HKD structure :: (Type -> Type) -> Type) | |
Defined in Data.Generic.HKD.Types | |
type Rep (HKD structure f) | |
Defined in Data.Generic.HKD.Types |
class Build structure (f :: Type -> Type) k | f structure -> k #
With many HKD applications, we're working with types like Maybe
where it
makes sense for us to start with mempty
and add values in as we go.
This isn't always the case, however: if all the component parts of our type
are gathered using some IO
action, we'd like to construct something like
HKD MyType IO
, and IO a
isn't a Monoid
for all types a
. When this
happens, we need to pass in our parameters when we build our structure.
The build
function lets us construct our type by passing explicit values
for each parameter:
>>>
:set -XDeriveGeneric -XTypeApplications
>>>
:{
data User = User { name :: String, age :: Int, likesDogs :: Bool } deriving Generic :}
>>>
:{
test :: _ test = build @User :} ... ... Found type wildcard ... ... standing for ...f [Char] -> f Int -> f Bool -> HKD User f... ...
Once we call the build
function, and indicate the type we want to build,
we are free to pick whichever f
we like and get to work!
Instances
(Fill f structure xs, GBuild f structure xs k) => Build structure f k | |
Defined in Data.Generic.HKD.Build |
class Construct (f :: Type -> Type) structure #
When working with the HKD representation, it is useful to have a way to convert to and from our original type. To do this, we can:
construct
the original type from our HKD representation, anddeconstruct
the original type into our HKD representation.
As an example, we can try (unsuccessfully) to construct an (Int, Bool)
tuple from an unpopulated partial structure.
>>>
:set -XTypeApplications
>>>
import Data.Monoid (Last)
>>>
construct (mempty @(HKD (Int, Bool) Last))
Last {getLast = Nothing}
We can also deconstruct a tuple into a partial structure:
>>>
deconstruct @[] ("Hello", True)
(,) ["Hello"] [True]
These two methods also satisfy the round-tripping property:
construct (deconstruct x) == [ x :: (Int, Bool, String) ]
Instances
(Applicative f, Generic structure, GConstruct f (Rep structure)) => Construct f structure | |
Defined in Data.Generic.HKD.Construction |