
z :: client -> Label client z client = undefined
ok :: (B.Label client ~ A.Label client) => client -> [A.Label client]. ok client = [ A.z client, B.z client]
This technique relies on the explicit management of the identities of modules both at compile-time (type annotation of D.ok) and run-time (creation of (D client) in the body of D.ok). While explicit management of modules at compile time is the point of the exercise, it would be better to avoid the passing of reified module identities at runtime.
In particular, this variant requires all bindings in the module to take an explicit parameter, instead of having a single parameter for the whole module. Having a single module-identifier parameter for each binding is better than having lots of individual parameters for each binding, but the idea of a parameterized module is to avoid these extra per-binding parameters alltogether. Of course, my variant cheated a little, using the TF "feature" that TF applications hide implicit parameters from contexts, so instead of 'Label a~type=>type', we write 'Label a'. (which meant I had to fix the 'a' to something concrete to avoid ambiguous types, as I needed to use type families, not data families, to get the sharing) Nevertheless, interesting possibilities. Claus