Easy iterative deepening of recursion depth

I am almost done with a directive and a meta-calling predicate that I have been working on.

The meta-calling predicate looks like this:

%!   call_iterating_depth(Goal, Options) is multi.
%  
%   Calls Goal successively trying deeper recursion depths until Goal succeeds.
%   * fails silently if Goal fails.
%   * Stops trying new depths on the first depth that succeeds.
%   * fails silently if the end(Depth) given as an option is reached.
%
%  Options:
%   * start(Start):   set initial depth to try, default 3.
%   * step(Step):   set increment between depths, default 1.
%   * end(End):     set last  depth to try, default `inf` (infinite)
 

I can contribute this code to the community if there is interest.

There is also a directive called :- iterate_depth PredIndicator which wraps the original predicate and allows iterating the recursion depth on existing predicates.

I am now writing the test cases, so I would appreciate any test scenarios that you can think of.

Also I am debating between inf and a large number for the default value for the end(Depth) option. What do you think makes more sense?

1 Like

I’d go for infinite (as between/3). inf is also an abbreviation for clp(fd) bounds meaning negative infinity.

One way to distribute is as a pack. It might be a nice thing for the library as well. I’m still a bit unsure what should be where. Most working eco systems seems to be working mostly with external packages.

I see, actually I was meaning to choose between inf and a large number like 20 000. inf would cause non-termination by default for predicates which are infinitely recursive and 20 000 will cause the predicate to terminate.

I chose inf because I can do Start =< End, with End == inf. I don’t think that will work with infinite.

If in the library I would think in the same place as the other limiting meta-calls, together with call_with_depth_limit/3 and the other ones. That seems reasonable to me.

Do you prefer a pack though?

I though Start =< inf would not work, but it does as inf is the arithmetic function for the float Inf NaN value. Not very elegant to rely on that, I fear. I would go for

( End == infinite -> true ; Start =< End )

It is a bit longer, but it compiles quite efficiently and doesn’t depend on corner cases.

Yes, except that these are built-ins. I want to keep the stuff in boot relatively small. What would make sense is to make a new real library and move this stuff together with your’s there. We only need a good library name, but we can combine all the resource limiting calls in there, possibly except for the call_with_time_limit/2 as that depends on nasty OS dependent stuff that doesn’t belong to the core.