A shelf is an object with multiple slots whose contents survive backtracking. The content of each slot can be set and retrieved individually, or the whole shelf can be retrieved as a term.
Shelves are referred to by handle, not by name, so they make it easy to write robust, reentrant code. A shelf disappears when the system backtracks over its creation, when the shelf handle gets garbage collected, or when it is explicitly destroyed.
A shelf is initialized from a compound term InitTerm. InitTerm's arity determines the number of slots the shelf provides, and InitTerm's arguments are used to initialize the corresponding shelf slots.
% a meta-predicate to count the number of solutions to a goal: count_solutions(Goal, Total) :- shelf_create(count(0), Shelf), ( call(Goal), shelf_inc(Shelf, 1), fail ; shelf_get(Shelf, 1, Total) ), shelf_abolish(Shelf). % finding the sum and maximum of data/1 facts: data(2). data(9). data(3). data(5). data(7). sum_and_max(Sum, Max) :- shelf_create(agg(0,0), Shelf), ( data(X), shelf_get(Shelf, 1, OldMax), ( X > OldMax -> shelf_set(Shelf, 1, X) ; true ), shelf_get(Shelf, 2, OldSum), NewSum is OldSum + X, shelf_set(Shelf, 2, NewSum), fail ; shelf_get(Shelf, 0, agg(Max, Sum)) ), shelf_abolish(Shelf). % if-then-else with backtracking over the condition: if(Cond, Then, Else) :- shelf_create(sol(no), SolFlag), ( call(Cond), shelf_set(SolFlag, 1, yes), % remember there was a solution call(Then) ; shelf_get(SolFlag, 1, no), % fail if there was a solution call(Else) ).