As some have discovered, I picked up the in-browser version of SWI-Prolog. See https://swi-prolog.discourse.group/t/wiki-discussion-swi-prolog-in-the-browser-using-wasm.
The problem is how to deal with blocking operations like Prolog’s read/1 and anything that reads. The JavaScript/browser model is event driven. So, JavaScript calling some predicate on Prolog to process an event is fine. Prolog having to wait for user input or some other event is not. Instead, control has to go back to JavaScript and JavaScript shall make the Prolog engine resume when the waited for data is available.
Ciao solved that by running Prolog in a separate web worker and using PostMessage to make the worker chat with main JavaScript. See https://oa.upm.es/71073/1/TFG_GUILLERMO_GARCIA_PRADALES.pdf
We can do the same (I guess), but we also have two alternatives. One was created after discussion with @maren: yield from a foreign predicate, i.e., a foreign predicate can ask the VM to return control to its caller, allowing the VM to be resumed later. The other is delimited continuations that do something similar, but I think they won’t work for this because control remains in the Prolog VM.
The idea would be that a blocking foreign predicate performs a yield, describing to JavaScript what it is waiting for, for example input. The JavaScript keeps dealing with the documents and its events and at some point realizes it may again resume Prolog. For example, we wait for a key-press (get_single_char/1). The predicate yields, on a KeyPress event, JavaScript stores the pressed key somewhere and resumes Prolog. Prolog picks up the key and continues.
The C side looks like this:
qid_t q = PL_open_query(....); // returns immediately
if ( (rc = PL_next_solution(q)) == PL_S_YIELD )
// pick up what we are waiting for and return to JavaScript
else
// Goal completed (handle results, close query and return to JavaScript)
Now my question is what this should look like from JavaScript? As is, we have a JavaScript function calling a Prolog goal from a string. From the above we get the same, but it may answer that this it is suspending, waiting for X.
If “mygoal” is at some point waiting for network data I imagine it could look like below (forgive my poor JavaScript). But what if we wait for the user to fill out some form and submit it? Ideally we’d have a reusable JavaScript function that can deal with all the things Prolog may be waiting for.
let rc = prolog.call("mygoal"))
if ( (url = is_fetch_request(rc)) )
fetch(url)
.then( (response) => response.json())
.then( (data) => prolog.resume(data));
// handle other things we might be waiting for
Note that on the long run we can possibly maintain various threads of control in Prolog waiting for different events using this as first level and delimited continuations as secondary level
Anyone?