tau-prolog: consult doesn't call initialization/1 directive goals

the consult JavaScript function doesn’t call initialization/1 directive goals. For example, with:

session.consult( ":- initialization(write(hello))." );
session.query( "true." );
session.answers( x => console.log( pl.format_answer(x) ) );

we get:

$ node ./tp.js 
true ;
false.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 32 (21 by maintainers)

Commits related to this issue

Most upvoted comments

Great! Please feel free to add the header that you consider appropriate. You can distribute it under the same Logtalk license.

This (d84181b) is the last major change in the Tau Prolog interface. Thread.prototype.query becomes asynchronous due to goal expansion. @pmoura Hopefully this is the last change for your script: 😄

var readlineSync = require("readline-sync");
var pl = require("./node_modules/tau-prolog/modules/core.js");
require("./node_modules/tau-prolog/modules/format.js")(pl);
require("./node_modules/tau-prolog/modules/js.js")(pl);
require("./node_modules/tau-prolog/modules/lists.js")(pl);
require("./node_modules/tau-prolog/modules/os.js")(pl);
require("./node_modules/tau-prolog/modules/random.js")(pl);
require("./node_modules/tau-prolog/modules/statistics.js")(pl);

var max_answers = process.argv[2] || 100;
var session = pl.create(50000);
var compose = (f,g) => x => f(g(x));
var show = x => console.log(pl.format_answer(x, session));
var repl = function() {
    var query = readlineSync.question("?- ", {keepWhitespace: true}) + "\n";
    session.query(query, {success: function(_goal) {
        session.answers(function(answer) {
            show(answer);
            if(answer === false || pl.type.is_error(answer))
                repl();
        }, max_answers);
    }, error: compose(repl, show)});
};
session.consult("../logtalk3/adapters/unsupported/tau.pl", {success: function() {
    session.consult("../logtalk3/paths/paths.pl", {success: function() {
        session.consult("../logtalk3/core/core.pl", {success: function() {
            repl();
        }, error: show});
    }, error: show});
}, error: show});

Thanks for debugging the issue. I would never guessed a Tau bug in the op/3 directive! I will update and resume testing.

Sorry, it was a bug with the op/3 directive. I just tried logtalk and now it works correctly.

Ok, let me do some experiments with your latest changes.

But that’s the problem. Consult cannot be asynchronous as a file may depend on a file that must complete loading before. My understanding of that JavaScript snippet is that it provides a solution to make consult synchronous. But that doesn’t seem to be possible when using the consult/1 predicate.

consult/1 is asynchronous in the sense that the Tau Prolgo thread “falls asleep” until the file has finished loading, and then resolution continues. A file is not loaded until the previous one is loaded.

How is this reflected in the consult predicate?

The consult/1 built-in predicate should not be affected, since it was already asynchronous as it was incorporated into the Tau Prolog resolution logic. Maybe you could load your files more comfortably with Tau Prolog:

var session = pl.create(20000);
session.query(`
consult('file 1'),
consult('file 2'),
consult('file 3'),
logtalk_load(hello_world(loader)).
`);
session.answers(x => console.log(pl.format_answer(x, session)));

This is an important change in the consult process, since from now on the consult method is also an asynchronous process. consult accepts success option to be executed when the parsing is end, and error option to report an error:

var session = pl.create(20000);
var show = x => console.log(pl.format_answer(x, session));
session.consult("../logtalk3/adapters/unsupported/tau.pl", {success: function() {
    session.consult("../logtalk3/paths/paths.pl", {success: function() {
        session.consult("../logtalk3/core/core.pl", {success: function() {
            session.query("logtalk_load(hello_world(loader)).");
            session.answers(show);
        }, error: show});
    }, error: show});
}, error: show});

The query method will also require this change due to the goal expansion.

But that’s not standard behavior and it breaks existing code. They must be called after the file is parsed. The solution seems to be collecting all initialization goals from session.consult() calls and then call the goals (in the order the directives were found; this is also key) after the file is fully parsed.

But there’s another bug: initialization/1 directives must be called only after a file is finished loading. In the current implementation, the initialization goals seem to being called as soon as the directives are parsed. The solution could be calling the initialization goals right before the query (i.e. when processing the session.query() call).