2
votes

I have app that modifies the fact db. I want to have the ability to roll-back the changes i.e. return to original state if rule fails at some point in between. Like a DB transaction. Does prolog provide something along the lines? If not how would you approach such problem?

thanks


changing db facts are 4-5 different type of facts f.e. :

f1(x,y).
f1(x1,y1).
f2(a,b).
f3(d,f).
....
f5(u,m).
f5(r,g).

I modify the fact db, with assert and retract. Currently I modify only single fact at a time. But the modification routines could be called multiple times. Also currently I can assert fact dynamically, but use retract only to modify a fact i.e. retract->assert sequence. By "app" I meant the app I'm writing, so I have full control of what I do.

2
What is the "app"? What is the "fact db"? How do you modify the "fact db". Answer all my questions in your question. thanksUser

2 Answers

2
votes

It really depends on your actual problem (describing it better in your question would be very useful). By far the easiest way to model a problem like you have described is to use backtracking instead of manipulating the database.

This, however, would mean that you would have to rethink your approach. Instead of using the database as your temporary store, you only use the database for ground truths. Then, you collect a state in a logical variable.

Since you have not given enough detail, I would try to explain what I mean by a made up silly example.

Say you have a bunch of things that you want to sort. You are unaware that Prolog lets you sort, and instead take the following highly inefficient approach:

  • Make a permutation of your things;
  • Check if the permutation is sorted.

So here are your things:

t(foo).
t(bar).
t(baz).
t(foobar).
t(foobarbaz).
t('just another thing').
t(t).

Here is a predicate that checks if things are sorted in increasing order:

is_sorted([]).
is_sorted([X|Xs]) :-
    is_sorted_1(Xs, X).

is_sorted_1([], _).
is_sorted_1([X|Xs], Prev) :-
    Prev @=< X,
    is_sorted_1(Xs, X).

Here now gets interesting. We have the things as ground facts. We collect them in a list, and use this list as a starting point of our silly sort.

permutation_sort_ts(Sorted_ts) :-
    findall(T, t(T), Ts),
    permutation_sort(Ts, Sorted_ts).

A permutation sort does what it says. It takes a list, makes a permutation of it, and checks if the result is sorted.

permutation_sort(L, S) :-
    permutation(L, S),
    is_sorted(S).

Here is what happens when we run the predicate from the top level:

?- permutation_sort_ts(R).
R = [bar, baz, foo, foobar, foobarbaz, 'just another thing', t] ;
false.

What happens? In the predicate permutation_sort/2, we generate one possible permutation at a time, and check if it is sorted. If the permutation was not sorted, the predicate fails, and backtracks to the last choice point. All bindings done after the choice point are "forgotten": you don't need to clean the permutation that was not sorted because Prolog simply forgets about it! So, a new permutation is generated and checked whether it is sorted.

Most importantly, you are not changing the database at any point. Instead, you are using logic variables to keep a state of your computation. If you are not sure about what is going on exactly, try to trace:

?- trace(permutation_sort/2).
?- permutation_sort_ts(R).
% you should see how permutation are checked in turn

Doing it the way you seem to suggest in your question would mean that for each permutation, you insert the list in the database, check if it is sorted, and if it not, you retract if from the database before continuing your search. This is not how Prolog is meant to be used!

But please ask a more focused question if you want a more useful answer.

1
votes

a difficult question...

Prolog doesn't handle transaction in traditional sense, mainly because is not a database in traditional sense. Indeed, traditional (relational) databases need multiple languages to be able to express procedural details, and usually doesn't consider the order of records as relevant, while in Prolog the order is the main way to control execution... then transactions what mean in Prolog context ? when execution backtracks, it is on 'rollback' ?

Searching from transaction in SWI-Prolog, we see that either RDF store, ODBC, Berkley DB interface, or SQLite pack offer transaction management.

For something simpler, I think that library(persistency) should work. Just reload the state on rollback... The file(s) handled by the library are plain Prolog terms, so the data storage evolution can be easily 'debugged'

edit

I just stumbled upon the docstore pack. It could be the better choice...