Unable to make facts dynamic in SWI-Prolog - prolog

I would like to be able to retract and assert facts dynamically for the procedure location:
location(egg, duck_pen).
Based on advice online (including No permission to modify static procedure), I've tried adding each of the following to my source code, which otherwise contains only the above assertion:
dynamic location/2.
dynamic(location/2).
dynamic(location)/2.
The first two versions give me this error at compile-time (when loaded into SWI-Prolog):
No permission to redefine built-in predicate `(dynamic)/1'
Use :- redefine_system_predicate(+Head) if redefinition is intended
The last version does not give me an error at compile-time, but, whether I put it at the beginning or end of the file, I get an error when I try retracting my fact:
?- retract(location(egg,duck_pen)).
ERROR: retract/1: No permission to modify static procedure `location/2'
I am using SWI-Prolog version 6.6.5.

Use
:- dynamic location/2.
location(X, Y) blah blah

Related

Assertz causing "no permission to modify static procedure" error

I am trying to define initial position of the agent as direction/2:
direction(1, west).
And then define a predicate to change agent's direction:
turnLeft(T) :-
TNext is T+1,
direction(T, west), assertz(direction(TNext, north)),!,
direction(T, south), assertz(direction(TNext, west)),!,
direction(T, east), assertz(direction(TNext, south)),!,
direction(T, north), assertz(direction(TNext, east)).
However, when I invoke i.e. turnLeft(1), a following error occurs:
No permission to modify static procedure `direction/2'
I am using online SWISH IDE, does it have anything to do with it or does the problem lie in something else?
Predicates are static by default. To make a predicate dynamic, i.e. to allow its definition to change at runtime by asserting and retracting clauses for it, you need to use the standard dynamic/1 predicate directive.
Add at the top of the file the directive:
:- dynamic(direction/2).

On ways to work around an unexpected "Undefined procedure" error

NB: Just to be clear, my motivation for the question below is to learn my way around Prolog and SWI-Prolog, not to get past a particular error message. In fact, I already know one way to get past this error. My question asks about whether several other alternatives are also possible.
An exercise in my Prolog textbook asks one to describe the outcome one should expect from several queries, assuming one has consulted the following knowledgebase beforehand:
x(a).
z(b).
z(c).
z(d).
w(V) :- x(V).
w(V) :- y(V).
w(V) :- z(V).
On SWI-Prolog, at least, most of these queries fail, because SWI-Prolog intreprets y as undefined.
From the solutions to the exercises at the end of the book I can tell that this is not the authors' intended outcome. Maybe there's a Prolog implementation for which the exercise would turn as the solution presents it.
Be that as it may, I'd like to learn about good ways to work around the problem.
Consider, for example, the query w(x).. the book's solution claims that the query w(x). should evaluate to false.. In fact, this is what happens:
?- w(x).
ERROR: w/1: Undefined procedure: y/1
Exception: (7) y(x) ?
(At this point, SWI-Prolog is expecting me to enter some letter indicating how to respond to the exception. More about this later.)
I'm looking for ways to either turn the interaction above to
?- w(x).
false.
?-
...or at least for a suitable <ONE-LETTER RESPONSE> I could give to SWI-Prolog so that it arrives at the conclusion false. IOW, so that
?- w(x).
ERROR: w/1: Undefined procedure: y/1
Exception: (7) y(x) ? <ONE-LETTER RESPONSE>
false.
?-
I know of at least one answer to my question, namely simply to delete or comment out the line:
w(V) :- y(V).
I would like to know of other possible solutions, such as, for example, the "suitable " I alluded to earlier.
Another possibility would be some SWI-Prolog global configuration that would result in the above interaction to change to
?- w(x).
false.
?-
A third possibility would be to "define" y in some minimal way. The only way I can come up with is by adding the fact
y(dummy).
to the knowledgebase. Is there a more minimal way to define y, one that does not require introducing an extraneous constant into the domain of discourse?
(This is not specific to SWI)
The first Prolog systems back in the 1970s actually behaved in the way you describe. Soon it became apparent that this is a frequent source of errors. Simple misspellings remained undetected for too long. Current implementations produce a clean existence error. This is standard behaviour since 1995.
However, you can go back into the olden tymes with the ISO Prolog flag unknown which has three values error (default), fail, and warning.
?- inex.
ERROR: Undefined procedure: inex/0 (DWIM could not correct goal)
?- set_prolog_flag(unknown, fail).
Warning: Using a non-error value for unknown in the global module
Warning: causes most of the development environment to stop working.
Warning: Please use :- dynamic or limit usage of unknown to a module.
Warning: See http://www.swi-prolog.org/howto/database.html
true.
?- inex.
false.
?- set_prolog_flag(unknown, warning).
Warning: Using a non-error value for unknown in the global module
Warning: causes most of the development environment to stop working.
Warning: Please use :- dynamic or limit usage of unknown to a module.
Warning: See http://www.swi-prolog.org/howto/database.html
true.
?- inex.
Warning: toplevel: Undefined procedure: inex/0 (DWIM could not correct goal)
false.
As you can read above, SWI proposes to use a dynamic declaration in stead - which in turn has its own problems... It is much better to declare instead:
:- discontiguous(y/1).
An undefined procedure error raises an exception so if you want the exception to be raised because you don't want to change y/1 predicate (delete or define it) you need to catch the exception and then return false like this:
x(a).
z(b).
z(c).
z(d).
w(V) :- x(V).
w(V) :- catch(y(V), error(Err,_Context),my_handler(Err)).
w(V) :- z(V).
my_handler(Err):- write(Err),fail.
Example:
?- w(x).
existence_error(procedure,y/1)
false.

Prolog: subsets facts not working

I've never written in Prolog before. I have to provide facts so that when it runs it displays:
?- subset([a,b],[a,c,d,b]).
true.
?-include([],[a,b]).
true.
So far, I've written this:
subset([],_Y).
subset([X|T],Y):- member(X,Y),subset(T,Y).
But include doesn't work when I write include([],[a,b]). . It shows this:
ERROR: toplevel: Undefined procedure: include/2 (DWIM could not correct goal)
Any help would be appreciated. Thanks
You get the error because you didn't define the predicate include/2. Your given example looks like include/2 should be describing the same relation as subset/2. So you can either rename your definition from subset/2 to include/2 and then run the query or you can use subset/2 to define include/2:
include(X,Y) :-
subset(X,Y).
Note that in order to use member/2 you have to use library(lists). However, in some Prolog systems (e.g. SWI) this library includes a predicate subset/2 thus leading to a warning when you consult your source file:
Warning: ...
Local definition of user:subset/2 overrides weak import from lists
If you want to implement your own version of subset/2 anyway and not get this warning, you can rename your predicate or not use library(lists) and implement your version of member/2, for example:
subset([],_Y).
subset([X|T],Y) :-
element_in(X,Y),
subset(T,Y).
element_in(X,[X|_]).
element_in(X,[Y|Ys]) :-
dif(X,Y),
element_in(X,Ys).

current_predicate/1 does not work with :- dynamic?

I have some predicates that I define using asserts in Prolog.
I am using current_predicate/1 in order to know whether the assert has been run or not (only one value needs to be asserted).
However, swipl keeps complaining:
Warning: The predicates below are not defined. If these are defined
Warning: at runtime using assert/1, use :- dynamic Name/Arity.
Warning:
Warning: amountOfStudentsInCourseAsserted/2, which is referenced by
So, I added the :- dynamic amountOfStudentsInCourseAsserted/2, but unfortunately, this adds the predicate to the current_predicate(Predicate).. Therefore I cannot use current_predicate/1 anymore if I am using this dynamic naming.
Is there another predicate like current_predicate/1that isn't true for dynamic names?
You can use in alternative the predicate_property/2 built-in predicate and the number_of_clauses/1 property.
The :- dynamic declaration is appropriate, as it will make the symbol known in the database. Then just attempt to match (with appropriate arguments, ignored in the following sample) before asserting:
...
( amountOfStudentsInCourseAsserted(_,_)
-> true
; assert(amountOfStudentsInCourseAsserted(X,Y))
),
...

I want to create dynamic facts in prolog

I wrote the following simple code, and I expect that when I write 'male.', this code ask me once "is it male?" and if i input 'No' it write on screen "she is female".
male :- ( print('is it male ? '),read(yes)) -> true; asserta( not(male)),female.
female:- not(male),print('she is female').
not(P) :- (call(P) -> fail ; true) .
but this code has following error:
uncaught exception: error(permission_error(modify,static_procedure,not/1),asserta/1);
the error in swi-prolog is :
ERROR: asserta/1: No permission to modify static_procedure `not/1'
As gusbro said, not/1 is a predefined static procedure (and therefore it is not a good idea to use the same name). However, this is not the reason you get the error in swi-prolog as you can overwrite the standard definition:
?- assert(not(42)).
true.
?- not(42).
true.
the problem is that you have already defined not/1 in your code and, when you do not declare a predicate explicitly as dynamic, swi-prolog will assume that it's static and will not allow you to change it.
You can declare it as dynamic by inserting this line in your code:
:-dynamic(not/1).
I think that this will not solve the problem in other prolog implementations (eg gnu-prolog) as the error message says permission_error(modify,static_procedure,not/1); in any case it is highly recommended to change the name.
By the way, it would be simpler and cleaner to simply test what the argument is and print the corresponding message. If, however, you want to create something more complex (using a state maybe) you could use global variables since they are more efficient that assert/retract.

Resources