Prolog - ASSERT and RETRACT - prolog

I was wondering, I am aware you can use assert to add facts or rules or whatever if you have declared the predicate to be -:dynamic, but this only allows the changes that are made to be kept in that session only, e.g. if you close the Prolog window then the database changes are lost.
So I was wondering, is there any way of making it so that the assert and retract predicates can make permanent changes to the Prolog .pl file?
Thanks

I can suggest you a very simple way of doing this.
1 ?- assert(a(1)).
true.
2 ?- assert(a(2)).
true.
3 ?- assert(a(3)).
true.
4 ?- a(A).
A = 1 ;
A = 2 ;
A = 3.
5 ?- tell('a_db.txt'), listing(a), told.
true.
Then close session, reopen.
1 ?- a(A).
ERROR: toplevel: Undefined procedure: a/1 (DWIM could not correct goal)
2 ?- ['a_db.txt'].
% a_db.txt compiled 0.00 sec, 516 bytes
true.
3 ?- a(A).
A = 1 ;
A = 2 ;
A = 3.
4 ?- listing(a).
:- dynamic a/1.
a(1).
a(2).
a(3).
true.

Related

Prolog argument mode indicator causes output false

I am trying to use Prolog's argument mode indicators in the signature of my method (https://www.swi-prolog.org/pldoc/man?section=argmode).
Without the indicators, my function works as expected (eg. palindrome([1,2,1]) gives true):
palindrome(List) :-
reverse(List, List)
But when I say
palindrome(+List) :-
reverse(List, List)
I get false every time. I don't get any errors or warnings. I also tried the following but had no luck:
palindrome(+List) :-
reverse(+List, +List)
So I'm pretty sure I am using these indicators wrong somehow. Can anyone help? I am using SWI-Prolog and the SWISH online IDE.
Yes, wrong. You shouldn't be using them at all, in the code. Only in the comments.
+ is interpreted as a separate token:
6 ?- atom(+X).
false.
7 ?- +X =.. Z.
Z = [+, X].
8 ?- +X = + X.
true.
9 ?- +X = '+'(X).
true.
You could use the +-using predicate definition as you show, but it's rather pointless:
14 ?- [user].
bar(+X,+X).
|:
true.
15 ?- bar( + 1, +Z).
Z = 1.
There are languages that do let us declare the modes, like I think Mercury does. But not Prolog. In Prolog we only use this as comments, to guide our use and understanding of the code.

SWI-Prolog: Call 3=2+1 -> Fail: 3=2+1

I'm working on something in Prolog and I wanted to check, at some point in my proogram, if some variable1 equals variable 2 + 1 (var1=var2+1). It said false. Variable1 is equal to 3 in my case, and var2 is equal to 2. It doesn't register as true and I can't understand why. I tried to 'trace' it, but still can't understand what the problem is, it just fails.
In Prolog 2+1 is just 2+1, or more canonical +(2,1). After all, it is only because some people see + as addition that 2+1 is equivalent to 3.
You can use is/2 [swi-doc] to evaluate an arithmetic expression, for example:
?- X is 2+1.
X = 3.
?- 3 is 2+1.
true.
You can also =:=/2 [swi-doc] to check if the two operands are equivalent if these are evaluated arithmetically:
?- 3 =:= 2+1.
true.
?- 4 =:= 2+1.
false.

Prolog: stop condition?

Here's a very trivial Prolog knowledge base:
spouse(bill,cheryl).
married(X,Y) :- spouse(X,Y).
married(X,Y) :- spouse(Y,X).
I ran the following queries. Note that sometimes the answer is the correct name (only), but other times the answer is the correct name and "false".
1 ?- married(bill,X).
X = cheryl ;
false.
2 ?- married(cheryl,X).
X = bill.
3 ?- married(X,bill).
X = cheryl.
4 ?- married(X,cheryl).
X = bill ;
false.
Can someone explain this seemingly inconsistent behavior? Thanks in advance.
The false response from Prolog means that Prolog had a choice point to go back to in an attempt to find further answers and it found no more. The order in which your predicates and facts are set up can impact whether it thinks it has more choices to explore.
In the given case:
spouse(bill,cheryl).
married(X,Y) :- spouse(X,Y).
married(X,Y) :- spouse(Y,X).
1 ?- married(bill,X).
X = cheryl ;
false.
2 ?- married(cheryl,X).
X = bill.
3 ?- married(X,bill).
X = cheryl.
4 ?- married(X,cheryl).
X = bill ;
false.
In the two false cases, the query married/2 is satisfied by the first of two married/2 clauses. Once satisified, Prolog realizes it has another choice to make (the second married/2 clause), and prompts for you to look for more. You press ;, then Prolog explores the second (and final) clause, finds no more solutions, and comes back false.
Swap the order of your married/2 clauses and see what happens:
spouse(bill,cheryl).
married(X,Y) :- spouse(Y,X).
married(X,Y) :- spouse(X,Y).
?- married(bill,X).
X = cheryl.
?- married(cheryl,X).
X = bill ;
false.
?- married(X,bill).
X = cheryl ;
false.
?- married(X,cheryl).
X = bill.
As expected, the results are reversed since we've changed which queries are satisfied by the first clause.
The false response can appear inconsistent to beginning Prolog programmers and "feel" like an error or warning, but it's actually a perfectly normal Prolog response. Prolog is quite consistent in its behavior of attempting to find solutions and, when no more choices exist, will return false. If Prolog has exhausted all the other choices before it finds the final solution, it displays the solution and doesn't return false (as in the case above in which the second clause is the only solution).
There is a temptation to try and "clean up" the false responses by using cuts. Although this can have the desired short-term result, it is risky since you are removing choice points from the predicate and as you add data and logic may eliminate solutions which you really want.
Thus, in the modified case:
spouse(bill,cheryl).
spouse(emma,nate).
married(X,Y) :- spouse(X,Y), !. % If we found the spouse, we're done, no more!
married(X,Y) :- spouse(Y,X).
?- married(bill,X).
X = cheryl.
?- married(cheryl,X).
X = bill.
?- married(X,bill).
X = cheryl.
?- married(X, cheryl).
X = bill.
Yay, life is good! But wait, what if we do this:
?- married(X,Y).
X = bill,
Y = cheryl.
?-
Are bill and cheryl the only married couple? No... it left out nate and emma. The cut eliminated the rest of the solutions.

SWI Prolog Database

is there a way I can query a SWI Prolog database to check if it doesn't contain an element?
I have tried using "not" but doesn't seem to work with this version of Prolog.
maybe you're looking for clause/2. A dummy session sample
1 ?- [user].
|: a(1).
|: a(2).
|: a(X) :- b(X).
|: b(3).
|: b(4).
% user://1 compiled 0.03 sec, 6 clauses
true.
2 ?- clause(a(X),Body).
X = 1,
Body = true ;
X = 2,
Body = true ;
Body = b(X).
3 ?- clause(b(X),Body).
X = 3,
Body = true ;
X = 4,
Body = true.
4 ?- clause(c(X),Body).
false.
you can see that c/1 is not defined...
Anyway, SWi-Prolog database is a complex beast, and it offers much more control about its contents.

Prolog - Assert into a new database

:-dynamic listofQuestions/2.
myrule:-
write('P = '), write(Percent), write('-'),write(X),
( listofQuestions(Percent,X) -> true ; assert(listofQuestions(Percent,X)) ),
The code snippet might not be required to answer my question.
I want to assert to a blank 'listofQuestions' everytime I call my rule. This only happens if I close my prolog window and restart it.
Any suggestions?
abolish/1 removes all clauses of a given predicate from the database. Hence, just add a call to abolish(PredName/Arity) whenever you need to remove the information about this predicate. Beware that after abolishing the call to the dynamic predicate does not fail but reports an error.
12 ?- f(X,Y).
false.
13 ?- assert(f(a,b)).
true.
14 ?- f(X,Y).
X = a,
Y = b.
15 ?- abolish(f/2).
true.
16 ?- f(X,Y).
ERROR: user://2:67:
toplevel: Undefined procedure: f/2 (DWIM could not correct goal)
In SWI-Prolog, abolish works on static procedures, unless the prolog flag iso is set to true. If you intend to remove only dynamic predicates, you should better try retractall. Observe that in this case removal does not lead to an error being reported but to a failure.
17 ?- [user].
:- dynamic f/2.
|:
% user://3 compiled 0.00 sec, 264 bytes
true.
18 ?- f(X,Y).
false.
19 ?- assert(f(a,b)).
true.
20 ?- f(X,Y).
X = a,
Y = b.
21 ?- retractall(f(X,Y)).
true.
22 ?- f(X,Y).
false.

Resources