-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Toy dependency injection framework -- -- Toy dependency injection framework that wires things at runtime. @package cauldron @version 0.4.0.0 -- | This is a library for performing dependency injection. It's an -- alternative to manually wiring your functions and passing all required -- parameters explicitly. Instead of that, you throw your functions into -- a Cauldron, which wires them for you, guiding itself by the -- types. -- -- Wiring errors are detected at runtime, not at compile time. -- -- This library should be used at the "composition root" of the -- application, and only there: the components we are wiring together -- need not be aware that the library exists. -- --
--   >>> :{
--   data A = A deriving Show
--   data B = B deriving Show
--   data C = C deriving Show
--   makeA :: A
--   makeA = A
--   makeB :: A -> B
--   makeB = \_ -> B
--   makeC :: A -> B -> IO C
--   makeC = \_ _ -> pure C
--   :}
--   
-- --
--   >>> :{
--   do
--     let cauldron :: Cauldron IO
--         cauldron =
--           emptyCauldron
--           & insert @A do makeBean do pack value makeA
--           & insert @B do makeBean do pack value makeB
--           & insert @C do makeBean do pack effect makeC
--         Right (_ :: DependencyGraph, action) = cook forbidDepCycles cauldron
--     beans <- action
--     pure do taste @C beans
--   :}
--   Just C
--   
module Cauldron -- | A map of Bean recipes. Parameterized by the monad m in -- which the Bean Constructors might have effects. data Cauldron (m :: Type -> Type) emptyCauldron :: forall (m :: Type -> Type). Cauldron m -- | Put a recipe for a Bean into the Cauldron. -- -- Only one recipe is allowed for each different bean type, so -- insert for a bean will overwrite previous recipes for -- that type. insert :: forall bean (m :: Type -> Type). Typeable bean => Bean m bean -> Cauldron m -> Cauldron m -- | Tweak an already existing Bean recipe. adjust :: forall bean (m :: Type -> Type). Typeable bean => (Bean m bean -> Bean m bean) -> Cauldron m -> Cauldron m delete :: forall {k} (bean :: k) (m :: Type -> Type). Typeable bean => Cauldron m -> Cauldron m -- | Change the monad used by the beans in the Cauldron. hoistCauldron :: (forall x. () => m x -> n x) -> Cauldron m -> Cauldron n -- | A bean recipe, to be inserted into a Cauldron. data Bean (m :: Type -> Type) bean [Bean] :: forall (m :: Type -> Type) bean. Constructor m bean -> Decos m bean -> Bean m bean -- | A Bean without decorators, having only the main constructor. makeBean :: forall (m :: Type -> Type) a. Constructor m a -> Bean m a setConstructor :: forall (m :: Type -> Type) bean. Constructor m bean -> Bean m bean -> Bean m bean setDecos :: forall (m :: Type -> Type) bean. Decos m bean -> Bean m bean -> Bean m bean overDecos :: forall (m :: Type -> Type) bean. (Decos m bean -> Decos m bean) -> Bean m bean -> Bean m bean -- | Change the monad used by the bean's Constructor and its -- Decos. hoistBean :: (forall x. () => m x -> n x) -> Bean m bean -> Bean n bean -- | A list of Constructors for the decorators of some Bean. -- -- Constructors for a decorator will have the bean itself -- among their arguments. That bean argument will be either the -- "bare" undecorated bean (for the first decorator) or the result of -- applying the previous decorator in the list. -- -- Decorators can have other dependencies besides the bean. data Decos (m :: Type -> Type) bean -- | Empty list of decorators. emptyDecos :: forall (m :: Type -> Type) bean. Decos m bean -- | Build the decorators from a list of Constructors, first -- innermost, last outermost. fromConstructors :: forall (m :: Type -> Type) bean. [Constructor m bean] -> Decos m bean -- | Add a new decorator that modifies the bean after all existing -- decorators. -- -- This means the behaviours it adds to the bean's methods will be -- applied first when entering the method. addOuter :: forall (m :: Type -> Type) bean. Constructor m bean -> Decos m bean -> Decos m bean -- | Add a new decorator that modifies the bean before all existing -- decorators. -- -- This means the behaviours it adds to the bean's methods will be -- applied last, just before entering the base bean's method. -- -- Usually addOuter is preferrable. addInner :: forall (m :: Type -> Type) bean. Constructor m bean -> Decos m bean -> Decos m bean -- | Change the monad used by the decorators. hoistDecos :: (forall x. () => m x -> n x) -> Decos m bean -> Decos n bean -- | A way of building some bean value, potentially requiring some -- dependencies, potentially returning some secondary beans along the -- primary bean result, and also potentially requiring some -- initialization effect in a monad m. -- -- Note that only the type of the primary bean is reflected in -- the Constructor type. Those of the dependencies and secondary -- beans are not. -- -- A typical initialization monad will be IO, used for example to -- create mutable references that the bean will use internally. Sometimes -- the a constructor will allocate resources with bracket-like -- operations, and in that case a monad like Managed might be -- needed instead. data Constructor (m :: Type -> Type) bean -- | Take a curried function that constructs a bean, uncurry it recursively -- and then apply a Packer to its tip, resulting in a -- Constructor. -- --
--   >>> :{
--   data A = A deriving Show
--   data B = B deriving Show
--   data C = C deriving Show
--   makeB :: A -> B
--   makeB = \_ -> B
--   makeC :: A -> B -> IO C
--   makeC = \_ _ -> pure C
--   constructorB :: Constructor IO B
--   constructorB = pack value makeB
--   constructorC :: Constructor IO C
--   constructorC = pack effect makeC
--   :}
--   
-- -- There are pack0, pack1... functions which work for -- specific number of arguments, but the generic pack should work -- in most cases anyway. pack :: forall (args :: [Type]) r curried (regs :: [Type]) bean (m :: Type -> Type). (MulticurryableF args r curried (IsFunction curried), All (Typeable :: Type -> Constraint) args, All (And (Typeable :: Type -> Constraint) Monoid) regs) => Packer m regs bean r -> curried -> Constructor m bean -- | Slightly simpler version of pack for 0-argument -- functions. pack0 :: forall (regs :: [Type]) (m :: Type -> Type) bean r. All (And (Typeable :: Type -> Constraint) Monoid) regs => Packer m regs bean r -> r -> Constructor m bean -- | Slightly simpler version of pack for 1-argument -- functions. pack1 :: forall arg1 r (m :: Type -> Type) (regs :: [Type]) bean. (Typeable arg1, All (And (Typeable :: Type -> Constraint) Monoid) regs) => Packer m regs bean r -> (arg1 -> r) -> Constructor m bean -- | Slightly simpler version of pack for 2-argument -- functions. pack2 :: forall arg1 arg2 r (m :: Type -> Type) (regs :: [Type]) bean. (Typeable arg1, Typeable arg2, All (And (Typeable :: Type -> Constraint) Monoid) regs) => Packer m regs bean r -> (arg1 -> arg2 -> r) -> Constructor m bean -- | Slightly simpler version of pack for 3-argument -- functions. pack3 :: forall arg1 arg2 arg3 r (m :: Type -> Type) (regs :: [Type]) bean. (Typeable arg1, Typeable arg2, Typeable arg3, All (And (Typeable :: Type -> Constraint) Monoid) regs) => Packer m regs bean r -> (arg1 -> arg2 -> arg3 -> r) -> Constructor m bean -- | Change the monad in which the Constructor's effects take place. hoistConstructor :: (forall x. () => m x -> n x) -> Constructor m bean -> Constructor n bean -- | Applies a transformation to the tip of a curried function, coaxing it -- into the shape expected by a Constructor, which includes -- information about which is the primary bean and which are the -- secondary ones. -- -- -- -- More complex cases might require valueWith, effectWith, -- or working with the Packer constructor itself. newtype Packer (m :: Type -> Type) (regs :: [Type]) bean r Packer :: (r -> m (Regs regs bean)) -> Packer (m :: Type -> Type) (regs :: [Type]) bean r -- | For pure constructors that return the bean directly, and do -- not register secondary beans. value :: forall (m :: Type -> Type) bean. Applicative m => Packer m ('[] :: [Type]) bean bean -- | For effectul constructors that return an m bean -- initialization action, and do not register secondary beans. effect :: Applicative m => Packer m ('[] :: [Type]) bean (m bean) -- |
--   >>> :{
--   data A = A deriving Show
--   data B = B deriving Show
--   makeB :: A -> (Sum Int, B)
--   makeB = \_ -> (Sum 1, B)
--   constructorB :: Constructor IO B
--   constructorB = pack (valueWith \(s,bean) -> regs1 s bean) makeB
--   :}
--   
valueWith :: forall (m :: Type -> Type) (regs :: [Type]) r bean. (Applicative m, All (And (Typeable :: Type -> Constraint) Monoid) regs) => (r -> Regs regs bean) -> Packer m regs bean r -- |
--   >>> :{
--   data A = A deriving Show
--   data B = B deriving Show
--   makeB :: A -> IO (Sum Int, B)
--   makeB = \_ -> pure (Sum 1, B)
--   constructorB :: Constructor IO B
--   constructorB = pack (effectWith \(s,bean) -> regs1 s bean) makeB
--   :}
--   
effectWith :: forall m (regs :: [Type]) r bean. (Applicative m, All (And (Typeable :: Type -> Constraint) Monoid) regs) => (r -> Regs regs bean) -> Packer m regs bean (m r) -- | Auxiliary type which contains a primary bean along with zero or more -- secondary beans. The secondary beans must have Monoid -- instances. data Regs (regs :: [Type]) bean -- | A primary bean without secondary beans. regs0 :: bean -> Regs ('[] :: [Type]) bean -- | A primary bean with one secondary bean. regs1 :: reg1 -> bean -> Regs '[reg1] bean -- | A primary bean with two secondary beans. regs2 :: reg1 -> reg2 -> bean -> Regs '[reg1, reg2] bean -- | A primary bean with three secondary beans. regs3 :: reg1 -> reg2 -> reg3 -> bean -> Regs '[reg1, reg2, reg3] bean -- | Build the beans using the recipes stored in the Cauldron. cook :: Monad m => Fire m -> Cauldron m -> Either BadBeans (DependencyGraph, m BoiledBeans) -- | Cook a list of Cauldrons. -- -- Cauldrons later in the list can see the beans in all previous -- Cauldrons, but not vice versa. -- -- Beans in a Cauldron have priority over the same beans in -- previous Cauldrons. cookNonEmpty :: Monad m => NonEmpty (Fire m, Cauldron m) -> Either BadBeans (NonEmpty DependencyGraph, m (NonEmpty BoiledBeans)) -- | Cook a hierarchy of Cauldrons. -- -- Cauldrons down in the branches can see the beans of their -- ancestor Cauldrons, but not vice versa. -- -- Beans in a Cauldron have priority over the same beans in -- ancestor Cauldrons. cookTree :: Monad m => Tree (Fire m, Cauldron m) -> Either BadBeans (Tree DependencyGraph, m (Tree BoiledBeans)) -- | Strategy for dealing with dependency cycles. -- -- (Terrible uninformative name caused by a metaphor stretched too far.) data Fire (m :: Type -> Type) -- | Forbid any kind of cyclic dependencies between beans. This is probably -- what you want. forbidDepCycles :: forall (m :: Type -> Type). Monad m => Fire m -- | Allow direct self-dependencies. -- -- A bean constructor might depend on itself. This can be useful for -- having decorated self-invocations, because the version of the bean -- received as argument comes "from the future" and is already decorated. -- (BEWARE: Pattern-matching too eagerly on this "bean from the -- future" during construction will cause infinite loops.) -- -- Note that a MonadFix instance is required of the initialization -- monad. allowSelfDeps :: forall (m :: Type -> Type). MonadFix m => Fire m -- | The successful result of cooking a Cauldron. Can't do a -- lot with them other than to taste them. data BoiledBeans -- | Return the resulting bean, if present. taste :: Typeable bean => BoiledBeans -> Maybe bean -- | Sometimes the cooking process goes wrong. data BadBeans -- | The Cauldron identified by PathToCauldron has beans that -- depend on beans that can't be found either in the current -- Cauldron or its ancestors. MissingDependencies :: PathToCauldron -> Map TypeRep (Set TypeRep) -> BadBeans -- | Beans that work both as primary beans and as secondary beans are -- disallowed. DoubleDutyBeans :: Set TypeRep -> BadBeans -- | Dependency cycles are disallowed by some Fires. DependencyCycle :: NonEmpty BeanConstructionStep -> BadBeans -- | Will always be [] when using cook; identifies a -- Cauldron in a hierarchy of Cauldrons when using -- cookNonEmpty or cookTree. type PathToCauldron = [Int] -- | An edge means that the source depends on the target. -- -- The dependencies of each bean are given separatedly from its -- decorators. data DependencyGraph -- | See the DOT format. exportToDot :: (BeanConstructionStep -> Text) -> FilePath -> DependencyGraph -> IO () defaultStepToText :: BeanConstructionStep -> Text -- | A step in the construction of a bean value. data BeanConstructionStep -- | Undecorated bean. BarePrimaryBean :: TypeRep -> BeanConstructionStep -- | Apply the decorator with the given index. Comes after the -- BarePrimaryBean and all PrimaryBeanDecos with a lower -- index value. PrimaryBeanDeco :: TypeRep -> Int -> BeanConstructionStep -- | Final, fully decorated version of a bean. If there are no decorators, -- comes directly after BarePrimaryBean. PrimaryBean :: TypeRep -> BeanConstructionStep -- | Beans that are secondary registrations of a Constructor and -- which are aggregated monoidally. SecondaryBean :: TypeRep -> BeanConstructionStep removeSecondaryBeans :: DependencyGraph -> DependencyGraph removeDecos :: DependencyGraph -> DependencyGraph -- | Unifies PrimaryBeans with their respective -- BarePrimaryBeans and PrimaryBeanDecos. -- -- Also removes any self-loops. collapsePrimaryBeans :: DependencyGraph -> DependencyGraph -- | Conversion to a graph type from the algebraic-graphs library -- for further processing. toAdjacencyMap :: DependencyGraph -> AdjacencyMap BeanConstructionStep instance GHC.Internal.Base.Applicative (Cauldron.Args args) instance GHC.Internal.Base.Applicative Cauldron.Extractor instance Data.Functor.Contravariant.Contravariant (Cauldron.Packer m regs bean) instance GHC.Classes.Eq Cauldron.BeanConstructionStep instance GHC.Internal.Base.Functor (Cauldron.Args args) instance GHC.Internal.Base.Functor Cauldron.Extractor instance GHC.Internal.Base.Functor (Cauldron.Regs regs) instance GHC.Internal.IsList.IsList (Cauldron.Decos m bean) instance GHC.Internal.Base.Monad (Cauldron.Args args) instance GHC.Internal.Base.Monoid (Cauldron.Cauldron m) instance GHC.Internal.Base.Monoid (Cauldron.Decos m bean) instance GHC.Classes.Ord Cauldron.BeanConstructionStep instance GHC.Internal.Base.Semigroup (Cauldron.Cauldron m) instance GHC.Internal.Base.Semigroup (Cauldron.Decos m bean) instance GHC.Internal.Show.Show Cauldron.BadBeans instance GHC.Internal.Show.Show Cauldron.BeanConstructionStep module Cauldron.Managed -- | This is a copy of the Managed type from the managed -- package, with a dodgy MonadFix instance tacked on. data Managed a -- | Build a Managed value from a withFoo-style -- resource-handling function that accepts a continuation, like -- withFile. -- -- Passing functions that do weird things like running their continuation -- twice will tear apart the fabric of reality. Why would you want -- to do that? Pass only withFoo-style functions. managed :: (forall r. () => (a -> IO r) -> IO r) -> Managed a -- | Make use of the managed resource by supplying a callback. with :: Managed a -> (a -> IO b) -> IO b instance GHC.Internal.Base.Applicative Cauldron.Managed.Managed instance GHC.Internal.Base.Functor Cauldron.Managed.Managed instance GHC.Internal.Control.Monad.Fix.MonadFix Cauldron.Managed.Managed instance Control.Monad.IO.Class.MonadIO Cauldron.Managed.Managed instance GHC.Internal.Base.Monad Cauldron.Managed.Managed