The binding minus operator is perfect when you know which names you want to remove from a binding, but what if you only know the names you want to leave in the binding?

Quick but Obscure

Suppose we want to remove every name in the binding B except thos in the binding restriction. There is a quick way to do that using the binding minus operator twice:

   1 B - (B - restriction)

The expression in parentheses will produce a binding with all the names in B that aren't in the binding restriction. When that is subtracted from B, the only names left will be the ones in restriction.

The down-side to this expression is that it depends on the complete set of names in both bindins. If the names in either binding change on a future evaluation, a cache miss will result.

Filtering with _map

A better way is to use the _map primitive function. That makes it possible to introduce dependencies only on the full set of names in one binding. For example:

   1   /**nocache**/
   2   restrict_binding(B, restriction)
   3   {
   4     /**nocache**/
   5     filter_one(n, v)
   6     {
   7       return if restriction!$n then [$n=B/$n] else [];
   8     };
   9     return _map(filter_one, B);
  10   };

This implementation will _map over every name in B and only pass through those in restriction.

Reversing the _map

We may be able to do better. By using _map over B, we will still introduce dependencies on all the names in B. If there are typically many more names in B than there are in restriction, we would be better off using _map on restriction:

   1   /**nocache**/
   2   restrict_binding(B, restriction)
   3   {
   4     /**nocache**/
   5     filter_one(n, v)
   6     {
   7       return if B!$n then [$n=B/$n] else [];
   8     };
   9     return _map(filter_one, restriction);
  10   };

Combined _map Implementation

It would be ideal if we could simply test which has more names, B or restriction. Unfortunately, due to the way dependencies are represented this would inadvertently create a dependency on the full set of names in both bindings. (There is no "number of elements in a binding" dependency, only a "set of names in binding" dependency.)

However we can give the caller the choice:

   1   /**nocache**/
   2   restrict_binding(B, restriction,
   3                    map_over_B=FALSE)
   4   {
   5     filter = if map_over_B then restriction else B;
   6     map_over = if map_over_B then B else restriction;
   7     /**nocache**/
   8     filter_one(n, v)
   9     {
  10       return if filter!$n then [$n=B/$n] else [];
  11     };
  12     return _map(filter_one, map_over);
  13   };