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