danidiaz / dep-t

Dependency injection for records-of-functions.
http://hackage.haskell.org/package/dep-t
BSD 3-Clause "New" or "Revised" License
8 stars 2 forks source link

Add `AccumConstructor` type synonym #25

Closed danidiaz closed 2 years ago

danidiaz commented 2 years ago

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:

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.

danidiaz commented 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)
danidiaz commented 2 years ago

Done 3e7e6d4.