A findall query results in C++ returns variables instead of values

I’m using SWI-Prolog version SWI-Prolog version 8.4.2 for x86_64-linux, with CLPFD.

My prolog code is very simple, it looks like this:

:- use_module(library(clpfd)).

example(N1, N2) :-
  N1 #= 4,
  N2 #= 1.

When I query the software using command line utility, the program works as expected.

?- findall([N1,N2],example(N1,N2),Z).
Z = [[4, 1]].

Now I want to use C++ code to retrieve the same findall query results. My C++ code looks like this:

int main(int argc, char **argv)
{
  PlEngine engine(argv[0]);

  try
  {
    cout << "Executing query..." << endl;

    PlTermv avv(3);
    avv[0] = PlCompound("[N1,N2]");
    avv[1] = PlCompound("example(N1,N2)");

    // Creates a PlQuery from the arguments generates the first next_solution() and destroys the query.
    // Returns the result of next_solution() or an exception.
    result = PlCall("findall", avv);
    cout << "\t" << (char *) avv[2] << endl;

    PlTail query_res_as_list(avv[2]);
    PlTerm query_res_01;
    int n = query_res_as_list.next(query_res_01);
    cout << "\t" << (char *) query_res_01 << endl;

    PlTail query_res_01_as_list(query_res_01);
    PlTerm query_res_01_item;
    n = query_res_01_as_list.next(query_res_01_item);
    cout << "\t" << (char*) query_res_01_item << endl;

    return 0;
  }
  catch ( PlException &ex )
  {
    cerr << (char *) ex << endl;
    exit(1);
  }
}

But what I’m getting is variables without the actual numbers I was expecting, namely 4 and 1:

Executing query...
        [[_2098,_2104]]
        [_2098,_2104]
        _2098

Can someone help me understand what I am doing wrong?

The reason it goes wrong is that in the code below the variables in avv[0] are nor related to those in avv[1] as variables are scoped to the term being converted.

    avv[0] = PlCompound("[N1,N2]");
    avv[1] = PlCompound("example(N1,N2)");

I refactored the code to the code below. The trick is to create the goal from a single term and now
use call/1. Then take the 3rd argument to get the list. I changed the [N1,N2] to ex(N1,N2) as the default char conversion will translate a list of small integers into a string. In any case, the golden rule formulated by Richad O’Keefe is that one should never use a list if the number of elements is always the same.

Finally, if you want to enumerate results and use them in C(++), use class PlQuery which nicely gives you the results one by one instead of collecting them in Prolog first.

#include <iostream>
#include <SWI-cpp.h>
#include <SWI-Stream.h>
using namespace std;

int main(int argc, char **argv)
{
  PlEngine engine(argc, argv);

  try
  {
    cout << "Executing query..." << endl;

    PlTermv avv(1);
    avv[0] = PlCompound("findall(ex(N1,N2), example(N1,N2), L)");

    int result = PlCall("call", avv);

    PlTail list(avv[0][3]);
    cout << "dumping the list ..." << endl;
    cout << (char*)list << endl;

    cout << "dumping elements ..." << endl;
    PlTerm e;
    while(list.next(e))
      cout << "\t" << (char *)e << endl;

    return 0;
  }
  catch ( PlException &ex )
  {
    cerr << (char *) ex << endl;
    exit(1);
  }
}
2 Likes