Closed danidiaz closed 2 years ago
Not very difficult as it turns out:
type AccumConstructor (env :: Type) (w :: Type) = (->) env `Compose` (,) w `Compose` Identity
fixEnvAccum :: (Phased env_, Typeable env_, Typeable m, Monoid w, Typeable w) =>
env_ (AccumConstructor (env_ Identity m) w) m ->
(w, env_ Identity m)
fixEnvAccum env =
let f = pullPhase <$> pullPhase env
(w, finalEnv) = f finalEnv
in (w, finalEnv)
It could have a type like
It could potentially be useful for accumulating uniformly-typed values across all components. Values like:
ContT
-like actions that kickstart some background job, with access to loggers and other component dependencies.This would help follow the principle of "putting everything related to a component in the same place".
For example, imagine that the action that lauched some background thread for some component were a "method" of the component itself. Besides adding the component to the composition root, we would also have to remember to explicitly invoke the launch method once the environment has been constructed. We might forget to do that, and then wonder why the component isn't working as expected.
Instead, if we expect every component to provide some monoidal initializer (probably
mempty
for most components), we can aggregate the initializers and launch them all with a single invocation. Now adding a new component which has a background thread only requires us to change one place in the code: when we insert it in the composition root.The big question is how difficult would it be to make
AccumConstructor
work withPhased
andfixEnv
.