Access to variable names given by the user in top-level queries

These must be saved somewhere, because the top-level uses them to write the answers. Can module implementers get access to these?

See boot/topvars.pl, toplevel_var/2. If you have a convincing story why use code should have access to these we can create a public API. I don’t see why you would want access to them. Note that they are not reliable in the sense that only “small” terms are stored, as defined by the Prolog flag toplevel_var_size

If you want to hack around, simply call toplevel_variables:toplevel_var/2. Don’t blame anyone if it stops working without notice though as it is a private API.

My use case is a meta-interpreter that solves queries according to an alternate resolution procedure. I think it generalizes to any meta-interpreter that must take over the final reporting rather than hand it back to the top-level.

In my case, there are two reasons for this. 1) The query is solved as a BDD over all of the possible models (ASP style, though with the traditional least Herbrand model semantics). The user’s query variables will only have bindings at top-level if they happen to be bound in the last model, which is incorrect because it suggests that they have this binding in all of the models. 2) The BDD is written to an SVG dot file rather than displayed. It would be large and not very useful to read. The written BDD relates the variables on internal nodes back to the query variables via Skolem functions over those variables. I need the user’s original names for this to be meaningful.

While I’m at it, is there a way to suppress the top-level display of bindings and constraints (since these will be misleading and not very informative)? Just success or ‘false’ will do.

Maybe I am missing the point, but you can always just enter your own interpreter and do whatever you feel like with the input and output? Use either read_term/2, one of the reading primitives, or even phrase_from_stream/2? Although for reading valid Prolog terms read_term/2 should be good enough:

meta_interpreter :-
    read_term(X, [variable_names(Names)]),
    format("Term: ~q ; Vars: ~q~n", [X, Names]).

Sorry for the silly example, but it shows how you can capture the names:

?- meta_interpreter.
|: hello(There).
Term: hello(_11832) ; Vars: ['There'=_11832]
true.

?- meta_interpreter.
|: something(Else).
Term: something(_13542) ; Vars: ['Else'=_13542]
true.

You can use prompt/2 if you don’t like the |:

My current interface predicate: ‘bdd(Query, File)’ lives naturally and anonymously in the SWI Prolog ecosystem once the user pulls it in via ‘use_module’. The user knows what it does from its arguments, and that it must be entered as a query at top-level with a full stop at the end, just like any other query. The user does not need to know about the meta-interpreter and any deviations from the top-level protocol it may require.

If I understand your proposal, I would need to change this to something like: ‘bdd(File)’. The user would need to know that an additional prompt for the query was coming next. I could print a message such as “Enter a query:” before the sub-prompt to aid in that understanding. The user would also need to know that a new full stop is required (unlike ‘y/n’ sub-prompts). Now knowing that he/she is in an interactive sub-level, the user might wonder whether they have to do anything to exit this level (as happens with debuggers).

I could avoid all of this if I can just get the query variable names. Jan has already pointed out how to do this. If it’s too difficult to suppress the display of bindings and constraints, I could live with that. The user knows that opening the resulting file in a browser will show the real results.

I think that the expand_query/4 and expand_answer/2 can get you want you want. The first allows you to inspect and possibly modify the query. It provides the variable names as Bindings. The second allows you to modify the answer bindings. A small problem might be that you do not have the query at hand. You could solve that by putting it in a global variable in expand_query/4. I think you simply get false or true using

 expand_answer(_, []).

not tested …

If you want to suppress the constraints, you can delete all attributes. The whole thing is backtracking anyway, so the deletion is not permanent.

Thanks, Jan. It occurred to me after I last posted that I could remove all of the attributes at the end to suppress constraint reporting. I was also thinking of finessing the bindings display by using fresh variables for the original query and binding the originals to something like ‘’. Your expand_answer approach is much simpler. I will look into expand_query/4 and expand_answer/2.

Follow up: I coded a test program incorporating the expand_query/4 and expand_answer/2 hooks, and it behaves exactly as I need – when executed stand-alone (in the user module). However, when I put the same code inside my module (where it needs to be) and export the two hooks through its interface spec, the hooks are never called at query time. When the user program is first consulted (containing a use_module directive), I get a warning for both hooks saying: “Local definition of user:(expand_…) overrides weak import from (module)”. There is, of course, no local definition, so I suppose the non-definition – i.e. do nothing – is taking precedence. How does a module get these hooks into the user module?

The hooks are traditionally in the user module. The new ones are in the prolog module. To add a hook from a module, do

:- multifile user:expand_query/4.

user:expand_query(...) :-
    ...

That is not modular, but hooks are not modular :frowning: