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?
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.
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.