1 Question: On ways to work around an unexpected "Undefined procedure" error

Question created on Sunday February 26, 2017

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?

3
2 answer                              3                         

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.
1
Sunday February 26, 2017

(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).
4
Sunday February 26, 2017
source posted here