-1

I'm thinking about getting all the traces of a prolog program in a list. For example, suppose I have

a.
v(1).
v(2).

test:-
    a,
    v(X).

I would like to obtain a list of the form [[a,v(1)],[a,v(2)]] (or something similar, I can always use findall at some time to get all the solutions).

The obvious idea that comes to my mind is to pre process the prolog code to add a list as argument to the predicate (using something like term_expansion/2 in SWI) and then, after each call, add the term to the list. For example:

test(L0):-
    a,
    append([],[a],L1),
    v(X),
    append(L1,[v(X)],L0).

The query would be findall(L,test(L),LO). obtaining LO = [[a, v(1)], [a, v(2)]]. Does anyone knows if there a predicate that already does this?

2
  • You want the full trace of execution or only the path that succeeds ? Because intermediate goasl may fail and backtrack and finally succeed. Commented Aug 2, 2021 at 20:55
  • Only the successful paths Commented Aug 2, 2021 at 21:16

3 Answers 3

1

I think you can do something like this:

successful_paths(Head, Paths) :-
    clause(Head, Body),
    findall(Path, successful_path(Body, Path), Paths).

successful_path((Goal, Goals), [Goal|Path]) :-
    !,
    call(Goal),
    successful_path(Goals, Path).

successful_path(Goal, [Goal]) :-
    call(Goal).

% Code to trace

a.
v(1).
v(2).

test:- a, v(_X).

Query:

?- successful_paths(test, Paths).
Paths = [[a, v(1)], [a, v(2)]].
Sign up to request clarification or add additional context in comments.

2 Comments

Note that in almost all Prolog systems, clause/2 can only be used with dynamic predicates.
Thanks, this is what I was looking for. I think there is no need to write call(Goal), simply Goal is enough.
0

This solution taps onto SWI debugger interface so its sort of a hack to keep track every goal using the builtin tracer (keeps the current trace on the dynamic database). It seems to work fine for simple queries like your example.

:-dynamic '$trace'/1.
get_trace(Pred, L):-
   retractall('$trace'(_)),
   assertz('$trace'([])),
   trace_notrace(t,t),
   call(Pred),
   call('$trace'(Trace)),
   trace_notrace(nt,nt),
   reverse(Trace, RTrace),
   maplist(arg(2), RTrace, L).

trace_notrace(t,_):-
  trace.
trace_notrace(T, _):-
  nodebug,
  T=nt.
trace_notrace(nt, T):-
  trace,
  T=t.

prolog_trace_interception(call, Frame, _PC, continue) :-
  retract('$trace'(Trace)),
  assertz('$trace'([frame(Frame, _Goal)|Trace])),
  !.
prolog_trace_interception(exit, Frame, _PC, continue) :-
  prolog_frame_attribute(Frame, goal, Goal),
  prolog_trace_interception_goal(Goal, Goal1),
  retract('$trace'(Trace)),
  (   append(Head, [frame(Frame, _)|MTrace], Trace)
  ->  append(Head, [frame(Frame, Goal1)|MTrace], NTrace)
  ;    NTrace=Trace
  ),
  assertz('$trace'(NTrace)),
  !.
prolog_trace_interception(fail, Frame, _PC, continue) :-
  retract('$trace'(Trace)),
  append(_, [frame(Frame, _)|NTrace], Trace),
  assertz('$trace'(NTrace)),
  !.
prolog_trace_interception(redo(_), Frame, _PC, continue) :-
  retract('$trace'(Trace)),
  append(_, [frame(Frame, Goal)|NTrace], Trace),
  assertz('$trace'([frame(Frame, Goal)|NTrace])),
  !.
prolog_trace_interception(_, _, _, continue).
    
prolog_trace_interception_goal(Goal, Goal2):-
  (
     (Goal=(Module:Goal1), memberchk(Module, [system, lists, '$bags']))
  -> copy_term(Goal1, Goal2)
  ;  copy_term(Goal, Goal2)
  ).

Sample runs:

?- findall(L, get_trace(test, L), Traces).
Traces = [[test, a, v(1)], [test, a, v(2)]].

?- get_trace(member(X, [a,b]), Trace).
X = a,
Trace = [member(a, [a, b])] ;
X = b,
Trace = [member(b, [a, b])] ;
false.

Comments

0

slago's answers is good, but nested predicates are not expanded. I've modified it as:

successful_paths(Head, Paths) :-
    clause(Head, Body),
    findall(Path, successful_path(Body, Path), Paths).

successful_path((Goal, Goals), [Goal|Path]) :-
    !,
    callable(Goal),
    successful_path(Goals, Path).

successful_path(Goal, Res) :-
    clause(Goal,Body),
    ( Body = true -> 
        Res = [Goal] ; 
        successful_path(Body,Res)
    ).

In this way, subgoals are expanded as well. This works with SWI prolog, since I've used callable(Goal) (i do not know whether it is standard or not). Otherwise, it can simply be replaced with call(Goal) or, even better, with Goal.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.