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 };