Jan Wielemaker 18 years ago
Permalink
Douglas,
*Post by **@users.sourceforge.net
:-ensure_loaded(depth_bound_varible_term_expanions).
p(X):-q(X).
q(a).
q(X):-p(X).
q(b).
converts into:
p(A):-depth_of_var(A,B),B<3,q(A).
q(a).
q(A):-depth_of_var(A,B),B<3,p(A).
q(b).
I think I understand your problem. It isn’t hard to code this at the
C-level. Below is the implementation. Save this file in
depth_of_var.c in the directory you built SWI-Prolog (you need a version
built from source) and build it using
plld -o depth_of_var -shared -I. -I…/src depth_of_var.c
Now use ?- load_foreign_library(depth_of_var).
to get your new predicate. NOTE NOTE NOTE: unlike normal foreign code
this code relies on details of the machinery normally not public. So,
it may stop working and you better recompile it before using it with
a new version of Prolog.
---cut here -----------------------------------------------------------
#include "pl-incl.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
depth_of_var(+Var, -Depth)
Dereference the term Var. If the dereferenced chain ends on the local
stack, return the call-depth difference between my parent frame and the
frame in which Var was created.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static foreign_t
depth_of_var(term_t var, term_t depth)
{ Word v = valTermRef(var);
LocalFrame fr = environment_frame;
long l0 = levelFrame(fr)-1; /* -1: Use my parent as reference */
deRef(v);
if ( onStackArea(local, v) )
{ DEBUG(0, Sdprintf("Ok, on local stack\n"));
while(fr && fr > (LocalFrame)v)
fr = parentFrame(fr);
if ( fr )
{ l0 -= levelFrame(fr);
return PL_unify_integer(depth, l0);
}
} else
DEBUG(0, Sdprintf("Not on local stack\n"));
fail;
}
install_t
install()
{ PL_register_foreign("depth_of_var", 2, depth_of_var, 0);
}
--cut here -----------------------------------------------------------
Here is the code I used to test:
:- load_foreign_library(depth_of_var).
q :-
q(X),
writeln(X).
q(X) :-
depth_of_var(X, D),
format('Depth = ~w~n', [D]),
D < 5,
q(X),
notail.
notail.
Running this says:
1 ?- q.
Depth = 1
Depth = 2
Depth = 3
Depth = 4
Depth = 5
No
You can adapt the code to throw an exception if the variable does not
origine in a local frame. The above version fails silently. The print
statements indicate what happens.
— Jan