9.5.2 Finding Multiple Solutions of a Call

If you are interested in more than one solution a more complicated scheme is used. You find the predicate definition as above, but you don't call the predicate directly.

  1. Set up a call with SP_open_query()
  2. Call SP_next_solution() to find a solution. Call this predicate again to find more solutions if there are any.
  3. Terminate the call with SP_close_query() or SP_cut_query()

The function SP_open_query() will return an identifier of type SP_qid that you use in successive calls, or 0, if given an invalid predicate reference. Note that if a new query is opened while another is already open, the new query must be terminated before exploring the solutions of the old one. That is, queries must be strictly nested:

     SP_qid SP_open_query(SP_pred_ref predicate, SP_term_ref arg1, ...)

The function SP_next_solution() will cause the Prolog engine to backtrack over any current solution of an open query and look for a new one. The given argument must be the innermost query that is still open, i.e. it must not have been terminated explicitly by SP_close_query() or SP_cut_query(). Returns SP_SUCCESS for success, SP_FAILURE for failure, SP_ERROR if an error condition occurred. Only when the return value is SP_SUCCESS are the values in the query arguments valid, and will remain so until backtracking into this query or an enclosing one:

     int SP_next_solution(SP_qid query)

A query must be terminated in either of two ways. The function SP_cut_query() will discard the choices created since the corresponding SP_open_query(), like the goal !. The current solution is retained in the arguments until backtracking into any enclosing query. The given argument does not have to be the innermost open query; any open queries in its scope will also be cut. Returns SP_SUCCESS for success and SP_ERROR for invalid usage:

     int SP_cut_query(SP_qid query)

Alternatively, the function SP_close_query() will discard the choices created since the corresponding SP_open_query(), and then backtrack into the query, throwing away any current solution, like the goal !, fail. The given argument does not have to be the innermost open query; any open queries in its scope will also be closed. Returns SP_SUCCESS for success and SP_ERROR for invalid usage:

     int SP_close_query(SP_qid query)

A simple way to call arbitrary prolog code is to use SP_read_from_string() (see Creating Prolog Terms) to create an argument to call/1. It is a good idea to always explicitly specify the module context when using call/1 or other meta-predicates from C.

This example calls a compound goal (without error checking).

     SP_pred_ref call_pred = SP_predicate("call", 1, "prolog");
     SP_term_ref x = SP_new_term_ref();
     SP_term_ref goal = SP_new_term_ref();
     SP_term_ref vals[] = {x, 0 /* zero termination */};
     long len;
     
     SP_put_variable(x);
     /* The X=_ is a trick to ensure that X is the first variable
        in the depth-first order and thus corresponds to vals[0] (x).
        There are no entries in vals for _,L1,L2.
     */
     SP_read_from_string(goal,
        "user:(X=_, length([0,1,2],L1), length([3,4],L2), X is L1+L2).", vals);
     
     SP_query(call_pred, goal);
     SP_get_integer(x, &len);
     /* here len is 5 */