Invoking Units: Every Which Way …

Units in PLT Scheme offer great promise in the area of parameterizing modular code. Rather than lean on require forms (or imports in other languages) for bringing identifier bindings into scope, Units offer programmatic parameterization. Instead of editing the source code of a module that depends on some other code, one can provide that parameter at, or close to, the ultimate use site of the fully realized Unit (perhaps in a module dedicated specifically to wiring together the components of an application). However, the reality isn’t always characterized by blue skies and smooth sailing. One area that has often bothered me is that if I create a Unit foo that depends on some unit exporting a signature setup^ (i.e. foo’s setup), the process of invoking foo can be somewhat cumbersome.

More specifically, I might have some unit g that exports the setup^ signature, so how do I go about invoking foo with g as a parameter? It sounds like I want something that looks like (foo g), but perhaps that’s not quite right since we often want the invocation of a Unit to add bindings to the caller’s lexical context. This explains why Unit invocation is actually done by forms such as define-values/invoke-unit or define-values/invoke-unit/infer. An emerging theme is that these are rather long names! To make matters worse, the /infer variants of Unit functions require that argument identifiers be bound by forms like define-unit. But that is a serious limitation, as illustrated in an earlier post.

If we set aside the /infer functionality, then define-values/invoke-unit itself leaves a bit to be desired since it requires explicit import and export annotations. But before we can even call define-values/invoke-unit we must link the Unit exporting setup^ to the Unit importing it, in our case, foo. This requires the creation of a compound-unit that specifies the necessary linking. Unfortunately, while that syntax is powerfully expressive, it is also somewhat scary compared to the initial hope for invocation syntax looking like (foo g).

To this end, I have written up several options for our example Unit invocation scenario. Each option may be uncommented (one at a time), and the entire module evaluated to see that bar is appropriately bound. The idea in these examples is that any helper functionality can be put into another module, while each Option represents a possible call-site syntax. The in-line unit expressions are also likely to be pulled in from elsewhere (e.g. one may have several back-end service providers expressed as Units that can be supplied to a client of any service exporting a particular signature).