# Using prolog\_walk\_code/1 to identify meta predicate calls?

**URL:** <https://swi-prolog.discourse.group/t/using-prolog-walk-code-1-to-identify-meta-predicate-calls/2977>\
**Category:** Nice to know\
**Created:** [September 26, 2020, 2:42pm UTC](https://swi-prolog.discourse.group/t/using-prolog-walk-code-1-to-identify-meta-predicate-calls/2977 "2020-09-26T14:42:31Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [September 26, 2020, 2:42pm UTC](https://swi-prolog.discourse.group/t/using-prolog-walk-code-1-to-identify-meta-predicate-calls/2977/1 "2020-09-26T14:42:31Z")

</div>

This is some example code that reveals a transformation of a call graph made by using [meta\_predicate/1](https://www.swi-prolog.org/pldoc/man?predicate=meta_predicate/1).

This is based on the blog [Using SWI-Prolog’s modules](https://chiselapp.com/user/ttmrichter/repository/gng/doc/trunk/output/tutorials/swiplmodtut.html).

[prolog\_walk\_code/1](https://www.swi-prolog.org/pldoc/doc_for?object=prolog_codewalk%3Aprolog_walk_code/1) is used to create the call graph as calls/2 facts. ([Example](https://www.swi-prolog.org/pldoc/doc/_SWI_/library/prolog_codewalk.pl))

Directory used for example: `C:\Users\Groot\Documents`

File: `add.pl`

```prolog
:- module('add',[
        add_all/2,
        add_some/3
    ]).

% :- meta_predicate add_some(-,1,-).

add_all(List,Sum) :-
    sum_list(List,Sum).

add_some(List,Goal,Sum) :-
    add_some_(List,Goal,Sum).

add_some_([],_,[]).
add_some_([H0|T0],Goal,R) :-
    (
        call(Goal,H0)
    ->
        R = [H0|T]
    ;
        R = T
    ),
    add_some_(T0,Goal,T).

```

File: `filters.pl`

```prolog
:- module('filters',[
        less_than_three/1
    ]).

less_than_three(N) :-
    integer(N),
    N < 3

```

File: `broken.pl`

```prolog
:- module('broken',[
]).

:- use_module(add).
:- use_module(filters).

go :-
    add_some([1,2,3,4,5], less_than_three, S),
    writeln(S).

```

File: `call_graph.pl`

```prolog
:- module('call_graph',[
        assert_call_graph/0
    ]).

:- dynamic
        calls/2.

assert_call_graph :-
        retractall(calls(_, _)),
        prolog_walk_code([ trace_reference(_),
                           on_trace(assert_edge),
                           source(true),
                           infer_meta_predicates(all),
                           verbose(true)
                         ]),
        predicate_property(calls(_,_), number_of_clauses(N)),
        format('Got ~D edges~n', [N]).

assert_edge(Callee, Caller, _Where) :-
        calls(Caller, Callee), !.
assert_edge(Callee, Caller, _Where) :-
        assertz(calls(Caller, Callee)).

```

Verify the code is broke

```bash
C:\Users\Groot>cd "C:\Users\Groot\Documents"
C:\Users\Groot\Documents>swipl -q -t broken:go,halt -f broken.pl
ERROR: add:add_some_/3: Unknown procedure: add:less_than_three/1
   Exception: (7) add:less_than_three(1) ? 

```

Load the code and use assert\_call\_graph/0.

```prolog
?- working_directory(_,'C:/Users/Groot/Documents').
true.

?- [call_graph,add,filters,broken].
true.

?- assert_call_graph.
% Found new meta-predicates in iteration 1 (5.406 sec)
% :- meta_predicate add:add_some_(*,1,*).
% :- meta_predicate prolog:generated_predicate(:).
% :- meta_predicate user:prolog_exception_hook(*,*,*,:).
% Restarting analysis ...
% Found new meta-predicates in iteration 2 (5.484 sec)
% :- meta_predicate add:add_some(*,1,*).
% Restarting analysis ...
Got 8,703 edges
true.

```

Save the calls/2 to file `calls (no meta).txt`

```prolog
?- tell('./calls (no meta).txt'), listing(call_graph:calls), told.
?- halt.

```

Thanks Jan W. ([ref](https://swi-prolog.discourse.group/t/using-prolog-walk-code-1-to-identify-meta-predicate-calls/2977/2))

File: `calls (no meta).txt`

```prolog
...

calls(add:add_some(A, B, C), add:add_some_(A, B, C)).
calls(add:add_some_([A|_], B, _), add:call(B, A)).
calls(add:add_some_([A|_], _, B), add:(B=[A|_])).
calls(add:add_some_([_|A], B, _), add:add_some_(A, B, _)).
calls(add:add_all(A, B), add:sum_list(A, B)).

...

calls(filters:less_than_three(A), filters:integer(A)).
calls(filters:less_than_three(A), filters:(A<3)).

...

calls(broken:go, broken:add_some([1, 2, 3, 4, 5], less_than_three, _)).
calls(broken:go, broken:writeln(_)).

...

```

Add meta\_predicate to add module.

```prolog
:- meta_predicate add_some(-,1,-).

```

Don’t forget to save the change.

Verify the code works

```bash
C:\Users\Groot>cd "C:\Users\Groot\Documents"
C:\Users\Groot\Documents>swipl -q -t broken:go,halt -f broken.pl
[1,2]

```

Load the code and use assert\_call\_graph/0.

```prolog
?- working_directory(_,'C:/Users/Groot/Documents').
true.

?- [call_graph,add,filters,broken].
true.

?- assert_call_graph.
% Found new meta-predicates in iteration 1 (6.234 sec)
% :- meta_predicate add:add_some_(*,1,*).
% :- meta_predicate prolog:generated_predicate(:).
% :- meta_predicate user:prolog_exception_hook(*,*,*,:).
% Restarting analysis ...
Got 7,991 edges
true.

```

Save the calls/2 to file `calls (meta).txt`

```prolog
?- tell('./calls (meta).txt'), listing(call_graph:calls), told.

```

File: `calls (meta).txt`

```prolog
...

calls(add:add_some(A, B, C), add:add_some_(A, B, C)).
calls(add:add_some_([A|_], B, _), add:call(B, A)).
calls(add:add_some_([A|_], _, B), add:(B=[A|_])).
calls(add:add_some_([_|A], B, _), add:add_some_(A, B, _)).
calls(add:add_all(A, B), add:sum_list(A, B)).

...

calls(filters:less_than_three(A), filters:integer(A)).
calls(filters:less_than_three(A), filters:(A<3)).

...

calls(broken:go, broken:add_some([1, 2, 3, 4, 5], less_than_three, _)).
calls(broken:go, broken:less_than_three(_)).
calls(broken:go, broken:writeln(_)).

...

```

NB

So adding

`:- meta_predicate add_some(-,1,-).`

to the module `add` the following call at the binary level (think meta predicate at the source level) is created

`calls(broken:go, broken:less_than_three(_)).`.

* * *

~~Was hoping gxref/0 could be used for finding such calls created via meta\_predicate, but I don’t know if it is possible or just did not find how it is done with gxref/0.~~

* * *

**EDIT**

trace/0 and gtrace/0 are aware of meta\_predicate/1

File: `library.pl`

```prolog
:- module(library, [my_call/1]).

:- meta_predicate(my_call(0)).

my_call(Goal) :-
    write('Calling: '),
    writeq(Goal), nl,
    call(Goal).

me(library).

```

File: `client.pl`

```prolog
:- module(client, [
        test_1/1
    ]).

:- use_module(library, [my_call/1]).

me(client).

% Me = client.
test_1(Me) :-
    my_call(me(Me)).

```

```prolog
[trace] ?- client:test_1(Me).
   Call: (10) client:test_1(_23106)
   Unify: (10) client:test_1(_23106)
^ Call: (11) library:my_call(me(_23106))
^ Unify: (11) library:my_call(client:me(_23106))
   Call: (12) write('Calling: ')
Calling: 
   Exit: (12) write('Calling: ')
   Call: (12) writeq(client:me(_23106))
client:me(_23106)
   Exit: (12) writeq(client:me(_23106))
   Call: (12) nl

   Exit: (12) nl
   Call: (12) client:me(_23106)
   Unify: (12) client:me(client)
   Exit: (12) client:me(client)
^ Exit: (11) library:my_call(client:me(client))
   Exit: (10) client:test_1(client)
Me = client.

```

The lines marked `^` indicate calls to [transparent predicates](https://www.swi-prolog.org/pldoc/man?section=ctxmodule), AKA meta predicates.

![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/1/119fea748c92f2b17836d02462986286b8221ddb.png)

See personal note in this [post](https://swi-prolog.discourse.group/t/descriptions-of-the-icons-glyphs-in-the-graphical-debugger/789/2) for table of icons used in Call Stack panel.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 26, 2020, 3:30pm UTC](https://swi-prolog.discourse.group/t/using-prolog-walk-code-1-to-identify-meta-predicate-calls/2977/2 "2020-09-26T15:30:03Z")

</div>

> [@EricGT](#):
>
> ```prolog
> ?- set_prolog_flag(color_term,false).
> ?- protocol("./calls (meta).txt").
> ?- listing(call_graph:calls).
> ?- noprotocol.
> 
> ```

Or, a bit simpler and not spamming your console:

```
?- tell('./calls (meta).txt'), listing(call_graph:calls), told.

```

> [@EricGT](#):
>
> Was hoping [gxref/0](https://www.swi-prolog.org/pldoc/doc_for?object=gxref/0) could be used for finding such calls created via meta\_predicate, but I don’t know if it is possible or just did not find how it is done with [gxref/0](https://www.swi-prolog.org/pldoc/doc_for?object=gxref/0).

gxref/0 works differently. It runs on top of library(prolog\_xref), which does _source_ analysis. The code walking library examines the _binary_ and thus examines all code while the source analysis can be incomplete because there are many ways how the actually loaded code may differ from the source (term/goal expansion, generated dynamic code, etc.)
