danidiaz / dep-t

Dependency injection for records-of-functions.

Home Page:http://hackage.haskell.org/package/dep-t

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add `AccumConstructor` type synonym

danidiaz opened this issue · comments

It could have a type like

type AccumConstructor (env :: Type) (w :: Type) = (->) env `Compose` (,) w `Compose` Identity

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.
  • Perhaps some Spring Boot actuator-like control endpoints.

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 with Phased and fixEnv.

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)