I think I found a solution, it’s a little hacky () but the proof of concept works:
wrap_test(Pred/Arity,Depth) :-
atom(Pred), integer(Arity), Arity>=0,
functor(Head,Pred,Arity),
set_flag(outside_recursion,0), % should be named inside_recursion
wrap_predicate(Head, ideepen, OrigPred,
(
format('inside wrapper~n'),
( get_flag(outside_recursion,IR),
IR == 0
-> set_flag(outside_recursion,1),
format('limit call',[]), call_with_depth_limit(OrigPred, Depth, RD),
( RD == depth_limit_exceeded
-> set_flag(outside_recursion,0)
; true
)
; format('regular call',[]), call(OrigPred)
)
)
).
leaf(l(_)).
btree(bt(A,B)) :-
( leaf(A); btree(A) ),
( leaf(B); btree(B) ).
Query
5 ?- call_with_depth_limit(btree(T),3,_).
T = bt(l(_8988), l(_8992)) ;
T = bt(l(_8988), bt(l(_8998), l(_9002))) ;
T = bt(bt(l(_8994), l(_8998)), l(_9002)) ;
T = bt(bt(l(_8994), l(_8998)), bt(l(_9008), l(_9012))) ;
true.
6 ?- wrap_test(btree/1,7).
true.
7 ?- btree(T).
inside wrapper
limit call
T = bt(l(_8592), l(_8596)) ;
inside wrapper
regular call
T = bt(l(_8592), bt(l(_8616), l(_8620))) ;
inside wrapper
regular call
T = bt(bt(l(_8612), l(_8616)), l(_8620)) ;
inside wrapper
regular call
T = bt(bt(l(_8612), l(_8616)), bt(l(_8640), l(_8644))) ;
true.
8 ?-
So it works fine, but with a strange change:
The depth of 3 in the top level corresponds to the depth of 7 inside the wrapper. I think it is because of the strange way in which call_with_depth_limit/3
counts the recursions. It took me ages to figure this one out.
Of course in the real implementation I will change the flag name to a generated ID based on the head.
Do you see any problem with this approach?
(I used flags because they are atomic, and probably faster than anything else).
EDIT: the name of the flag is wrong, it comes from a previous iteration. Should be called inside_recursion
but it doesn’t matter, because it needs to be generated anyway.