SWI-Prolog: how to insert a new clause to a databa

2019-08-09 09:17发布

I'm sorry, this has probably been asked before but I can't find a good answer.

I'm writing a Prolog assignment, in which we must write a database with insert, delete, etc. I'm currently stuck on the insert part. I'm trying to use tell, listing and told for this, but the results are often unpredictable, deleting random parts of the file. Here's the full code of my database, banco.pl:

:- dynamic progenitor/2.
progenitor(maria,joao).
progenitor(jose,joao).
progenitor(maria,ana).
progenitor(jose,ana).

insere(X,Y) :- dynamic progenitor/2, assert(progenitor(X,Y)).
tell('banco.pl'), listing(progenitor), told.

I then run the following on SWI-Prolog:

insere(luiz,luiza).

And get the following result on banco.pl:

:- dynamic progenitor/2.

progenitor(maria, joao).
progenitor(jose, joao).
progenitor(maria, ana).
progenitor(jose, ana).

Note that the clause I tried to insert isn't even in the file, and the lines defining commit and insere are missing.

How would I do this correctly?

标签: prolog
1条回答
beautiful°
2楼-- · 2019-08-09 09:48

tell starts writing to the beginning of the file. so you're overwriting everything else that was in the file. you have these options:

  1. put your progenitor predicate (and just that) in another file.

  2. use append/1 to write to the end of the file with portray_clause. this only helps for insert, but you stated that you want delete too.

  3. read the other clauses into a list and reprint them, then use listing/1 :

(text for formatting)

read_all_other_clauses(All_Other_Clauses):-
  see('yourfilename.pl'),
  read_all_other_clauses_(All_Other_Clauses,[]),
  seen.

read_all_other_clauses_(Other,Acc0):-
  (read(Clause) ->
   (Clause = progenitor(_,_) -> % omit those clauses, because they'll be printed with listing/1
     read_all_other_clauses_(Other,Acc0);
     read_all_other_clauses_(Other,[Clause|Acc0]));
   Other = Acc0). % read failed, we're done

operation(Insert, X,Y):-
    (call,(Insert) ->
      assert(progenitor(X,y));
      retract(progenitor(X,y))),
    read_all_other_clauses(Others),
    tell('yourfilename.pl'), % After the reading!
    maplist(portray_clause,Others), %Maplist is a SWI built-in, easy to rewrite, if you don't have it.
    listing(progenitor/2),
    told.

insert(X,Y):- operation(true,X,Y).
delete(X,Y):- operation(fail,X,Y).

Note that you could use the read_all_other_clauses for your delete only, if you change the line with the omit comment. Then you could use the solution proposed in #2 for your insere

查看更多
登录 后发表回答