Re: Multiple instances for embedded prolog interpreter

Stefan Radomski <[email protected]>
Newsgroups gmane.comp.ai.prolog.swi
Message-ID <78A29435-CC5A-43CB-B8EC-9FD4DAF4D700@tk.informatik.tu-darmstadt.de>
Hi again,

On Jul 24, 2013, at 2:05 PM, Jan Wielemaker <[email protected]> wrote:

> On 07/24/2013 01:37 PM, Stefan Radomski wrote:
>> Thank you again for the quick response,
>> 
>> On Jul 23, 2013, at 9:43 PM, Jan Wielemaker <[email protected]>
>>  wrote:
>> 
>>> Well, there is a lot of state around. Different engines have their
>>> own stacks, but indeed share predicates. If that is the `state' for
>>> which you want multiple instances you have two options: create
>>> thread_local declared predicates, which are predicates what have
>>> their own set of clauses in each thread (which is the same as each
>>> engine), or use modules. In each module you can have different sets
>>> of predicates that otherwise do not interact as long as you do not
>>> tell them to do so.
>> 
>> Let me give you some context here: We are using Prolog as an
>> ECMAScript replacement for scripting in XML documents (with good reasons
>> :). Our XML interpreter will take a set of such documents and interpret
>> them (in fact even a single document might nest others). As such, it is
>> imperative that the different Prolog scripting environments from the
>> different documents do not interfere with each other.
>> 
>> I can't see thread_local working in our situation as our
>> interpreters
>> are already multi-threaded and multiple threads are serialized via
>> mutexes to linearize access to all of the Prolog interpreter
>> (performance is a distant second atm). In the optimal solution, the
>> different documents' Prolog environments would behave as if there were
>> no others. It *is* working flawlessly if there is only one such document.
> 
> Using Prolog from multiple C++ threads is pretty trivial using the
> C Prolog engine API.  In any case, if you want to use the thread-local
> approach, you must use multiple Prolog engines.  It is a quite ok approach, provided you can enumerate the predicates that you will be
> using for storing an XML document beforehand, so you can declare all
> of them as thread_local.  Possibly a nice benefit is that the clauses
> die with the engine (as they are not accessible outside the engine it
> makes no sense to keep them).
> 

I do not use the SGML parser in SWI to parse the original XML document, they are stored in a C++ W3C compliant DOM implementation. In fact Prolog is only one among other possible scripting languages. I will only call into Prolog for expressions from a subset of elements and attributes, e.g. <if cond="..."> or <script>. Here is a sample XML file employing Prolog, that our interpreter will process [1]. This file does not show an embedded document, just imagine two of those being interpreted at the same time.

The problem with both approaches you outlined earlier (thread_local and modules) is e.g. that we allow something like <script src="…"> with src being an arbitrary .pl file which I just download and pass over to load_files at the moment. If I understand correctly, I would have to inspect the file and declare all its predicates as thread_local and juggle with the PL_engine_t's or move them into a module and qualify every possible way to establish facts with a unique namespace? Even for files included transitively from those .pl files. This might not even be possible if the file already defines a module and facts within.

>> I could imagine using the modules approach, but it is important that
> 
> Mapping each XML document to a module seems a more natural mapping to me.

That's what I was hoping to achieve with the "modules" approach.

> 
>> something like the following remains possible and is scoped to the
>> current document's environment:
>> 
>> <script>assert(event(foo)).</script>
>> 
>> I am perfectly free to do whatever I want with the Prolog runtime
>> before interpreting the contained prolog expression, but the author of
>> the XML must not be required to handle the module scoping aspect. I
>> tried to prefix every invocation of user supplied prolog with a
>> module/1, but did not get it to work:
>> 
>> C++ ---:
>> PlCall(("module(ns1)"));
>> PlCall("assert(sessionId(a1))");
>> PlCall("listing.");
>> 
>> PlCall(("module(ns2)"));
>> PlCall("assert(sessionId(a2))");
>> PlCall("listing.");
>> ---
>> 
>> It seems like asserted facts cannot be scoped in modules as the second listing/0
>> will show two sessionId facts:
> 
> module/1 sets the module for the toplevel query loop.  You are not talking to an interactive toplevel, so that is meaningless.  To insert
> in a module, use e.g.,
> 
>  PlCall("assert(ns1:sessionId(a2))");
> 
> Which is the same as this, which might be a bit handier if you do
> not want to look into the term.
> 
>  PlCall("ns1:assert(sessionId(a2))");
> 

But this assumes, that the content of the script tag I encountered was <script>ns1:assert(sessionId(a2))</script> and not <script>assert(sessionId(a2))</script>, thereby handing responsibility of modules/namespaces to the XML developers.

Inspecting each and every prolog expression (even those loaded from file) to define predicates as thread_local or move them into a module and qualify facts with a namespace seems so very unsatisfying and error-prone considering that it is working perfectly if there is only a single document with a single Prolog runtime. All I want is another instance of the prolog runtime, totally detached from the other ones without resorting to spawning new processes. :(

> Note that the C interface allows more explicit interaction with modules.
> Most of this is easily added to the C++ interface as well.  If you want
> to know what is possible, check out the C API documentation.

Skimming through SWI-Prolog.h does not reveal anything that would achieve what I need. If you could outline an approach that will spare me from inspecting all the prolog expressions at runtime (even those loaded from external files, which I cannot know a priori) as is the case with both the module and thread_local approach as far as I understand and isolate the different environments such that I can define facts and predicates that won't interfere, I'd be most grateful.

Isn't there something as conceptually simple as "get me another prolog environment"?

Regards
Stefan

[1] https://github.com/tklab-tud/uscxml/blob/master/test/samples/uscxml/test-prolog.scxml
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.