/*
You can implement a functor that does nothing but call whatever is passed to it ,
then in Your goal expansion promote Your expansion to use that functor ,
now Your goal expansion can check if a goal has already been promoted to use Your functor ,
in which case the expansion has already been done .
Example below rewrites every goal to use the “expanded” predicate
and does not rewrite any goal that is already an “expanded” goal .
IMHO it is a mistake to make the behaviour of goal_expansion different at a system level to tackle this problem .
A user may wish to see that goal come back again .
For example perhaps their implementation in goal_expansion uses assert or global variables
such that the second time around a different expansion is provoked .
~~~~~~~~ %&ZHcx;. ~~~~~~~~
*/
/*
?- [user] .
*/
expanded(_anything_) :- _anything_ .
goal_expansion(_saw_,_now_) :-
\+ _saw_ =.. [expanded|_] ,
my_goal_expansion(_saw_,_NOW_) ,
_now_ = expanded(_NOW_) .
my_goal_expansion(hello,writeln('hello')) .
my_goal_expansion(goodbye,writeln('goodbye')) .
test :-
hello ,
goodbye .
/*
end_of_file.
?- test .
hello
goodbye
true.
?- expand_goal(hello,G) .
G = expanded(writeln(hello)).
?- expand_goal(goodbye,G).
G = expanded(writeln(goodbye)).
?- expand_goal(whatever,G).
G = whatever.
?- [user] .
*/
my_goal_expansion(_saw_,_now_) :-
_enabled_ = tabling(enabled(_saw_)) ,
_stored_ = tabling(stored(_saw_)) ,
_store_ = assertz(tabling(stored(_saw_))) ,
_1_ = (\+ _enabled_ , _saw_ ) ,
_2_ = (_enabled_ , _stored_ ) ,
_3_ = (_enabled_ , \+ _stored_ , _saw_ , _store_) ,
_now_ = (_1_ ; _2_ ; _3_) .
tabling(enabled(foo(_))) .
foo(N) :-
between(0,10,N) ,
writeln(foo(N)) .
main :-
foo(N) ,
format("~N~10r~n",[N]) ,
false ;
true .
/*
end_of_file.
?- main .
0
1
2
3
4
5
6
7
8
9
10
?- tabling(stored(T)) , format("~N~q.~n",[T]) , false ; true .
foo(0).
foo(1).
foo(2).
foo(3).
foo(4).
foo(5).
foo(6).
foo(7).
foo(8).
foo(9).
foo(10).
*/