A recent addition to swi prolog is engines. These objects are self contained prolog engines with their own stack that maintaines the computation state and will generate each answer back stepwise. Guile log have implemented the same API and is reachable from the library (logic guile-log guile-prolog engine)
. A good introduction to these engines can be found at swi engines.
Let's consider the creation,
engine_create(+Template, :Goal, -Engine, +Options)
The idea is to copy_term
the Template and Goal simultaniusly and get a indipendent copy for the engine to work on and at yielding a return value a copy_term
of that is returned to the enclosing environment. Else everything should be independent.
The idea of guile-log and guile-log-prolog is that it want's to take advantage of a delicate state storage and restorage mechansim. We want the user to be able to stall a calculation and later restore it essentially passing back to the repl with some user data which can be manipulated for investigation and then restore the state and continue the calculation with some user choices added. The idea is that this would be the most powerful repl for deductive machines guided by humans. This means that in guile-log you can have an engine whithin and engine whithin an engine ... and still reach the shell with the storage of the overall state. Another issue is that many variables contained mutating state that should be safe for store / restore. This means that at change of state one need to copy the box values and restore them. Manually this is tedious and the semantics is plentiful for how you would like to maintain this global state. Where guile-log shines is it's toolbox to control these mutating boxes. So in guile-log we can do this,
?- engine_create
(X,
(
(X=1;X=2),
stall
),E,[alias(test)]),
engine_next(E,T1),
engine_next(E,T2).
stalled engine > e<test>
?- .s 1 %save current state in tag 1
?- .c %continue
stalled engine > e<test>
?- .s 2 %save current state in tag 2
?- .c %continue
E = e<test>,
T1 = 1,
T2 = 2.
?- .l 2 %load state stored in tag 2
?- .c % continue from tag 2
E = e<test>,
T1 = 1,
T2 = 2.
?- .l 1 % load tag 1
?- .c
stalled engine > e<test>
?- .c
E = e<test>,
T1 = 1,
T2 = 2.
In the next main version of guile, (2.2) there have been a lot of work to enable green threads or fibers. This means that when you get to a blocking io, you will let go for another fiber to run. This is cooparative scheduling and with scheme's delimied continuations you get some really smooth code for executing this. Guile log is enabled to work well with this and you can expect guile-log-prolog to support fibers in the near future.
Green threads or fibers or nice in that maintaining state consistancy is dead simple. If you just can make sure to yield to the scheduler and not risk freezing out other threads - this is the pay you have to do. Assume all fx
below spawn an engine with potential blocking io at which time the next fiber is invoked etc.
g :- f1(X),f2(X),,,,f100(X).
we see that they share state. An engine can be dependant and when a shared variable is unified, it can check for consistancy and add a unifying postprocessing construct knowing that all other engines in the conjunction is not running and complete each unification witout yielding to another fiber in the midle of it. It also means that each thread can fail early e.g. it can early see that X=1
fails when X
have been bound to 2 in another fiber. To make this work seamlessly and effectively is difficult but it turns out that guile-log has the right infrastructure to make this work well without too much hazzle. All this is not implemented but is on the drawing board. I will blog with examples when it is implemented. I just fired up guile 2.1.4 which has supports of the right toolbox for io operations.
Happy Hacking