Safe Haskell  None 

Language  Haskell2010 
This module provides helpers for building dependency injection environments composed of records.
It's not necessary when defining the record components themselves, in that case Dep.Has should suffice.
>>>
:{
type Logger :: (Type > Type) > Type newtype Logger d = Logger { info :: String > d () }  data Repository d = Repository { findById :: Int > d (Maybe String) , putById :: Int > String > d () , insert :: String > d Int }  data Controller d = Controller { create :: d Int , append :: Int > String > d Bool , inspect :: Int > d (Maybe String) }  type EnvHKD :: (Type > Type) > (Type > Type) > Type data EnvHKD h m = EnvHKD { logger :: h (Logger m), repository :: h (Repository m), controller :: h (Controller m) } deriving stock Generic deriving anyclass (FieldsFindableByType, DemotableFieldNames, Phased) deriving via Autowired (EnvHKD Identity m) instance Autowireable r_ m (EnvHKD Identity m) => Has r_ m (EnvHKD Identity m) :}
The module also provides a monad transformerless way of performing dependency
injection, by means of fixEnv
.
Synopsis
 class Has r_ (m :: Type > Type) (env :: Type)  env > m
 newtype TheDefaultFieldName (env :: Type) = TheDefaultFieldName env
 newtype TheFieldName (name :: Symbol) (env :: Type) = TheFieldName env
 class FieldsFindableByType (env :: Type) where
 type FindFieldByType env (r :: Type) :: Symbol
 newtype Autowired (env :: Type) = Autowired env
 type Autowireable r_ (m :: Type > Type) (env :: Type) = HasField (FindFieldByType env (r_ m)) env (Identity (r_ m))
 class Phased (env_ :: (Type > Type) > (Type > Type) > Type) where
 traverseH :: forall (h :: Type > Type) (f :: Type > Type) (g :: Type > Type) (m :: Type > Type). (Applicative f, Typeable f, Typeable g, Typeable h, Typeable m) => (forall x. h x > f (g x)) > env_ h m > f (env_ g m)
 liftA2H :: forall (a :: Type > Type) (f :: Type > Type) (f' :: Type > Type) (m :: Type > Type). (Typeable a, Typeable f, Typeable f', Typeable m) => (forall x. a x > f x > f' x) > env_ a m > env_ f m > env_ f' m
 pullPhase :: forall (f :: Type > Type) (g :: Type > Type) (m :: Type > Type) env_. (Phased env_, Applicative f, Typeable f, Typeable g, Typeable m) => env_ (Compose f g) m > f (env_ g m)
 mapPhase :: forall (f :: Type > Type) (f' :: Type > Type) (g :: Type > Type) (m :: Type > Type) env_. (Phased env_, Typeable f, Typeable f', Typeable g, Typeable m) => (forall x. f x > f' x) > env_ (Compose f g) m > env_ (Compose f' g) m
 liftA2Phase :: forall (a :: Type > Type) (f' :: Type > Type) (f :: Type > Type) (g :: Type > Type) (m :: Type > Type) env_. (Phased env_, Typeable a, Typeable f, Typeable f', Typeable g, Typeable m) => (forall x. a x > f x > f' x) > env_ (Compose a g) m > env_ (Compose f g) m > env_ (Compose f' g) m
 class DemotableFieldNames env_ where
 demoteFieldNamesH :: (forall x. String > h String x) > env_ (h String) m
 demoteFieldNames :: forall env_ m. DemotableFieldNames env_ => env_ (Constant String) m
 mapPhaseWithFieldNames :: forall (f :: Type > Type) (f' :: Type > Type) (g :: Type > Type) (m :: Type > Type) env_. (Phased env_, DemotableFieldNames env_, Typeable f, Typeable f', Typeable g, Typeable m) => (forall x. String > f x > f' x) > env_ (Compose f g) m > env_ (Compose f' g) m
 bindPhase :: forall f g a b. Functor f => f a > (a > g b) > Compose f g b
 skipPhase :: forall f g a. Applicative f => g a > Compose f g a
 fixEnv :: (Phased env_, Typeable env_, Typeable m) => env_ (Constructor (env_ Identity m)) m > env_ Identity m
 type Constructor (env :: Type) = (>) env `Compose` Identity
 constructor :: forall r_ m env. (env > r_ m) > Constructor env (r_ m)
 data InductiveEnv (rs :: [(Type > Type) > Type]) (h :: Type > Type) (m :: Type > Type) where
 AddDep :: forall r_ m rs h. h (r_ m) > InductiveEnv rs h m > InductiveEnv (r_ ': rs) h m
 EmptyEnv :: forall m h. InductiveEnv '[] h m
 addDep :: forall r_ m rs. r_ m > InductiveEnv rs Identity m > InductiveEnv (r_ ': rs) Identity m
 emptyEnv :: forall m. InductiveEnv '[] Identity m
 newtype Identity a = Identity {
 runIdentity :: a
 newtype Constant a (b :: k) = Constant {
 getConstant :: a
 newtype Compose (f :: k > Type) (g :: k1 > k) (a :: k1) = Compose {
 getCompose :: f (g a)
A generalpurpose Has
class Has r_ (m :: Type > Type) (env :: Type)  env > m Source #
A generic "Has" class. When partially applied to a parametrizable
recordoffunctions r_
, produces a 2place constraint that can used on its
own, or with Control.Monad.Dep.Class.
Instances
(FieldsFindableByType (env_ m), HasField (FindFieldByType (env_ m) (r_ m)) (env_ m) u, Coercible u (r_ m)) => Has r_ m (Autowired (env_ m)) Source #  
(Dep r_, HasField (DefaultFieldName r_) (env_ m) u, Coercible u (r_ m)) => Has r_ m (TheDefaultFieldName (env_ m)) Source #  
Defined in Dep.Env dep :: TheDefaultFieldName (env_ m) > r_ m Source #  
(HasField name (env_ m) u, Coercible u (r_ m)) => Has r_ m (TheFieldName name (env_ m)) Source #  
Defined in Dep.Env dep :: TheFieldName name (env_ m) > r_ m Source #  
InductiveEnvFind r_ m rs => Has r_ m (InductiveEnv rs Identity m) Source #  Works by searching on the list of types. 
Helpers for deriving Has
via the default field name
newtype TheDefaultFieldName (env :: Type) Source #
Helper for DerivingVia
HasField
instances.
It expects the component to have as field name the default fieldname
specified by Dep
.
This is the same behavior as the DefaultSignatures
implementation for
Has
, so maybe it doesn't make much sense to use it, except for
explicitness.
Instances
(Dep r_, HasField (DefaultFieldName r_) (env_ m) u, Coercible u (r_ m)) => Has r_ m (TheDefaultFieldName (env_ m)) Source #  
Defined in Dep.Env dep :: TheDefaultFieldName (env_ m) > r_ m Source # 
via arbitrary field name
newtype TheFieldName (name :: Symbol) (env :: Type) Source #
TheFieldName env 
via autowiring
class FieldsFindableByType (env :: Type) Source #
Class for getting the field name from the field's type.
The default implementation of FindFieldByType
requires a Generic
instance, but users can write their own implementations.
type FindFieldByType env (r :: Type) :: Symbol Source #
type FindFieldByType env r = FindFieldByType_ env r
newtype Autowired (env :: Type) Source #
Helper for DerivingVia
HasField
instances.
The fields are identified by their types.
It uses FindFieldByType
under the hood.
BEWARE: for large records with many components, this technique might incur in long compilation times.
Autowired env 
type Autowireable r_ (m :: Type > Type) (env :: Type) = HasField (FindFieldByType env (r_ m)) env (Identity (r_ m)) Source #
Constraints required when DerivingVia
all possible instances of Has
in
a single definition.
This only works for environments where all the fields come wrapped in Data.Functor.Identity.
Managing phases
class Phased (env_ :: (Type > Type) > (Type > Type) > Type) where Source #
Class of 2parameter environments for which the first parameter h
wraps
each field and corresponds to phases in the construction of the environment,
and the second parameter m
is the effect monad used by each component.
h
will typically be a composition of applicative functors, each one
representing a phase. We advance through the phases by "pulling out" the
outermost phase and running it in some way, until we are are left with a
Constructor
phase, which we can remove using fixEnv
.
Phased
resembles FunctorT, TraversableT and ApplicativeT from the barbies library. Phased
instances can be written in terms of them.
Nothing
:: forall (h :: Type > Type) (f :: Type > Type) (g :: Type > Type) (m :: Type > Type). (Applicative f, Typeable f, Typeable g, Typeable h, Typeable m)  
=> (forall x. h x > f (g x))  
> env_ h m  
> f (env_ g m) 
default traverseH :: forall (h :: Type > Type) (f :: Type > Type) (g :: Type > Type) (m :: Type > Type). (Applicative f, Typeable f, Typeable g, Typeable h, Typeable m, Generic (env_ h m), Generic (env_ g m), GTraverseH h g (Rep (env_ h m)) (Rep (env_ g m))) => (forall x. h x > f (g x)) > env_ h m > f (env_ g m) Source #
:: forall (a :: Type > Type) (f :: Type > Type) (f' :: Type > Type) (m :: Type > Type). (Typeable a, Typeable f, Typeable f', Typeable m)  
=> (forall x. a x > f x > f' x)  
> env_ a m  
> env_ f m  
> env_ f' m 
Used to implement liftA2Phase
, typically you should use that function instead.
default liftA2H :: forall (a :: Type > Type) (f :: Type > Type) (f' :: Type > Type) m. (Typeable a, Typeable f, Typeable f', Typeable m, Generic (env_ a m), Generic (env_ f m), Generic (env_ f' m), GLiftA2Phase a f f' (Rep (env_ a m)) (Rep (env_ f m)) (Rep (env_ f' m))) => (forall x. a x > f x > f' x) > env_ a m > env_ f m > env_ f' m Source #
Instances
Phased (InductiveEnv rs) Source #  
Defined in Dep.Env traverseH :: forall h f g (m :: Type > Type). (Applicative f, Typeable f, Typeable g, Typeable h, Typeable m) => (forall x. h x > f (g x)) > InductiveEnv rs h m > f (InductiveEnv rs g m) Source # liftA2H :: forall a f f' (m :: Type > Type). (Typeable a, Typeable f, Typeable f', Typeable m) => (forall x. a x > f x > f' x) > InductiveEnv rs a m > InductiveEnv rs f m > InductiveEnv rs f' m Source # 
:: forall (f :: Type > Type) (g :: Type > Type) (m :: Type > Type) env_. (Phased env_, Applicative f, Typeable f, Typeable g, Typeable m)  
=> env_ (Compose f g) m  
> f (env_ g m) 
Take the outermost phase wrapping each component and "pull it outwards", aggregating the phase's applicative effects.
:: forall (f :: Type > Type) (f' :: Type > Type) (g :: Type > Type) (m :: Type > Type) env_. (Phased env_, Typeable f, Typeable f', Typeable g, Typeable m)  
=> (forall x. f x > f' x)  
> env_ (Compose f g) m  
> env_ (Compose f' g) m 
Modify the outermost phase wrapping each component.
:: forall (a :: Type > Type) (f' :: Type > Type) (f :: Type > Type) (g :: Type > Type) (m :: Type > Type) env_. (Phased env_, Typeable a, Typeable f, Typeable f', Typeable g, Typeable m)  
=> (forall x. a x > f x > f' x)  
> env_ (Compose a g) m  
> env_ (Compose f g) m  
> env_ (Compose f' g) m 
Combine two environments with a function that works on their outermost phases.
Working with field names
class DemotableFieldNames env_ where Source #
Class of 2parameter environments for which it's possible to obtain the names of each field as values.
Nothing
demoteFieldNames :: forall env_ m. DemotableFieldNames env_ => env_ (Constant String) m Source #
Bring down the field names of the environment to the term level and store them in the accumulator of Data.Functor.Constant.
mapPhaseWithFieldNames Source #
:: forall (f :: Type > Type) (f' :: Type > Type) (g :: Type > Type) (m :: Type > Type) env_. (Phased env_, DemotableFieldNames env_, Typeable f, Typeable f', Typeable g, Typeable m)  
=> (forall x. String > f x > f' x)  
> env_ (Compose f g) m  
> env_ (Compose f' g) m 
Modify the outermost phase wrapping each component, while having access to the field name of the component.
A typical usage is modifying a "parsing the configuration" phase so that each component looks into a different section of the global configuration field.
Constructing phases
Small convenience functions to help build nested compositions of functors.
bindPhase :: forall f g a b. Functor f => f a > (a > g b) > Compose f g b Source #
Use the result of the previous phase to build the next one.
Can be useful infix.
skipPhase :: forall f g a. Applicative f => g a > Compose f g a Source #
Don't do anything for the current phase, just wrap the next one.
Injecting dependencies by tying the knot
fixEnv :: (Phased env_, Typeable env_, Typeable m) => env_ (Constructor (env_ Identity m)) m > env_ Identity m Source #
This is a method of performing dependency injection that doesn't require Control.Monad.Dep.DepT at all. In fact, it doesn't require the use of any monad transformer!
If we have a environment whose fields are functions that construct each component by searching for its dependencies in a "fully built" version of the environment, we can "tie the knot" to obtain the "fully built" environment. This works as long as there aren't any circular dependencies between components.
Think of it as a version of "Data.Function.fix" that, instead of "tying" a single function, ties a whole record of them.
The env_ (Constructor env_ m) m
parameter might be the result of peeling
away successive layers of applicative functor composition using pullPhase
,
until only the wiring phase remains.
type Constructor (env :: Type) = (>) env `Compose` Identity Source #
A phase with the effect of "constructing each component by reading its dependencies from a completed environment".
The Constructor
phase for an environment will typically be parameterized
with the environment itself.
constructor :: forall r_ m env. (env > r_ m) > Constructor env (r_ m) Source #
Turn an environmentconsuming function into a Constructor
that can be slotted
into some field of a Phased
environment.
Inductive environment with anonymous fields
data InductiveEnv (rs :: [(Type > Type) > Type]) (h :: Type > Type) (m :: Type > Type) where Source #
An inductively constructed environment with anonymous fields.
Can be useful for simple tests, and also for converting Has
based
components into functions that take their dependencies as separate
positional parameters.
makeController :: (Monad m, Has Logger m env, Has Repository m env) => env > Controller m makeController = undefined makeControllerPositional :: Monad m => Logger m > Repository m > Controller m makeControllerPositional a b = makeController $ addDep @Logger a $ addDep @Repository b $ emptyEnv
AddDep :: forall r_ m rs h. h (r_ m) > InductiveEnv rs h m > InductiveEnv (r_ ': rs) h m  
EmptyEnv :: forall m h. InductiveEnv '[] h m 
Instances
InductiveEnvFind r_ m rs => Has r_ m (InductiveEnv rs Identity m) Source #  Works by searching on the list of types. 
Phased (InductiveEnv rs) Source #  
Defined in Dep.Env traverseH :: forall h f g (m :: Type > Type). (Applicative f, Typeable f, Typeable g, Typeable h, Typeable m) => (forall x. h x > f (g x)) > InductiveEnv rs h m > f (InductiveEnv rs g m) Source # liftA2H :: forall a f f' (m :: Type > Type). (Typeable a, Typeable f, Typeable f', Typeable m) => (forall x. a x > f x > f' x) > InductiveEnv rs a m > InductiveEnv rs f m > InductiveEnv rs f' m Source # 
addDep :: forall r_ m rs. r_ m > InductiveEnv rs Identity m > InductiveEnv (r_ ': rs) Identity m Source #
emptyEnv :: forall m. InductiveEnv '[] Identity m Source #
Reexports
Identity functor and monad. (a nonstrict monad)
Since: base4.8.0.0
Identity  

Instances
Constant functor.
Constant  

Instances
newtype Compose (f :: k > Type) (g :: k1 > k) (a :: k1) infixr 9 #
Righttoleft composition of functors. The composition of applicative functors is always applicative, but the composition of monads is not always a monad.
Compose infixr 9  

Instances
Functor f => Generic1 (Compose f g :: k > Type)  Since: base4.9.0.0 
TestEquality f => TestEquality (Compose f g :: k2 > Type)  The deduction (via generativity) that if Since: base4.14.0.0 
Defined in Data.Functor.Compose  
(Functor f, Functor g) => Functor (Compose f g)  Since: base4.9.0.0 
(Applicative f, Applicative g) => Applicative (Compose f g)  Since: base4.9.0.0 
Defined in Data.Functor.Compose  
(Foldable f, Foldable g) => Foldable (Compose f g)  Since: base4.9.0.0 
Defined in Data.Functor.Compose fold :: Monoid m => Compose f g m > m # foldMap :: Monoid m => (a > m) > Compose f g a > m # foldMap' :: Monoid m => (a > m) > Compose f g a > m # foldr :: (a > b > b) > b > Compose f g a > b # foldr' :: (a > b > b) > b > Compose f g a > b # foldl :: (b > a > b) > b > Compose f g a > b # foldl' :: (b > a > b) > b > Compose f g a > b # foldr1 :: (a > a > a) > Compose f g a > a # foldl1 :: (a > a > a) > Compose f g a > a # toList :: Compose f g a > [a] # null :: Compose f g a > Bool # length :: Compose f g a > Int # elem :: Eq a => a > Compose f g a > Bool # maximum :: Ord a => Compose f g a > a # minimum :: Ord a => Compose f g a > a #  
(Traversable f, Traversable g) => Traversable (Compose f g)  Since: base4.9.0.0 
Defined in Data.Functor.Compose  
(Eq1 f, Eq1 g) => Eq1 (Compose f g)  Since: base4.9.0.0 
(Ord1 f, Ord1 g) => Ord1 (Compose f g)  Since: base4.9.0.0 
Defined in Data.Functor.Compose  
(Read1 f, Read1 g) => Read1 (Compose f g)  Since: base4.9.0.0 
Defined in Data.Functor.Compose liftReadsPrec :: (Int > ReadS a) > ReadS [a] > Int > ReadS (Compose f g a) # liftReadList :: (Int > ReadS a) > ReadS [a] > ReadS [Compose f g a] # liftReadPrec :: ReadPrec a > ReadPrec [a] > ReadPrec (Compose f g a) # liftReadListPrec :: ReadPrec a > ReadPrec [a] > ReadPrec [Compose f g a] #  
(Show1 f, Show1 g) => Show1 (Compose f g)  Since: base4.9.0.0 
(Alternative f, Applicative g) => Alternative (Compose f g)  Since: base4.9.0.0 
(Eq1 f, Eq1 g, Eq a) => Eq (Compose f g a)  Since: base4.9.0.0 
(Typeable a, Typeable f, Typeable g, Typeable k1, Typeable k2, Data (f (g a))) => Data (Compose f g a)  Since: base4.9.0.0 
Defined in Data.Functor.Compose gfoldl :: (forall d b. Data d => c (d > b) > d > c b) > (forall g0. g0 > c g0) > Compose f g a > c (Compose f g a) # gunfold :: (forall b r. Data b => c (b > r) > c r) > (forall r. r > c r) > Constr > c (Compose f g a) # toConstr :: Compose f g a > Constr # dataTypeOf :: Compose f g a > DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) > Maybe (c (Compose f g a)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) > Maybe (c (Compose f g a)) # gmapT :: (forall b. Data b => b > b) > Compose f g a > Compose f g a # gmapQl :: (r > r' > r) > r > (forall d. Data d => d > r') > Compose f g a > r # gmapQr :: forall r r'. (r' > r > r) > r > (forall d. Data d => d > r') > Compose f g a > r # gmapQ :: (forall d. Data d => d > u) > Compose f g a > [u] # gmapQi :: Int > (forall d. Data d => d > u) > Compose f g a > u # gmapM :: Monad m => (forall d. Data d => d > m d) > Compose f g a > m (Compose f g a) # gmapMp :: MonadPlus m => (forall d. Data d => d > m d) > Compose f g a > m (Compose f g a) # gmapMo :: MonadPlus m => (forall d. Data d => d > m d) > Compose f g a > m (Compose f g a) #  
(Ord1 f, Ord1 g, Ord a) => Ord (Compose f g a)  Since: base4.9.0.0 
Defined in Data.Functor.Compose compare :: Compose f g a > Compose f g a > Ordering # (<) :: Compose f g a > Compose f g a > Bool # (<=) :: Compose f g a > Compose f g a > Bool # (>) :: Compose f g a > Compose f g a > Bool # (>=) :: Compose f g a > Compose f g a > Bool #  
(Read1 f, Read1 g, Read a) => Read (Compose f g a)  Since: base4.9.0.0 
(Show1 f, Show1 g, Show a) => Show (Compose f g a)  Since: base4.9.0.0 
Generic (Compose f g a)  Since: base4.9.0.0 
type Rep1 (Compose f g :: k > Type)  
Defined in Data.Functor.Compose  
type Rep (Compose f g a)  
Defined in Data.Functor.Compose 