I'm studying for an exam and got stuck on one of the prep questions:
Question:
The following Prolog-program is a meta-program. Explain why this
program is a meta-program and give the output to the three questions
to the program:
?- prove(moving_method(bird,M),N).
?- prove(moving_method(ross,M),N).
?- prove(moving_method(kim,M),N).
I'm trying to run the code(on swish.swi-prolog.org) but it only gives me this error message:
Sandbox restriction!
Could not derive which predicate may be called from
call(C)
prove(A,B)
prove(moving_method(bird,A),B)
The code we are given:
:- dynamic moving_method/2, is_a/2.
is_a(bird,animal).
is_a(ross,albatross).
is_a(kim,kiwi).
is_a(albatross,bird).
moving_method(bird,fly).
moving_method(kiwi,walk).
prove(Fact,l):-
Fact,!.
prove(Fact,X):-
Fact=..[Rel,A1,A2],
is_a(A1,SA),
NewFact=..[Rel,SA,A2],
prove(NewFact,X1),
X is X1 + 1.
The error message might be fairly straight forward but how do I fix it? And why is this a meta-program?
Thank you!
why is this a meta-program?
See: SWI-Prolog Meta-Call Predicates
Meta-call predicates are used to call terms constructed at run time.
In this case passing in the predicate to call, Fact, then running it as a goal.
Related
I defined my knowledge base as:
edge(mammal,isa,animal).
edge(human,isa,mammal).
edge(simba,isa,human).
edge(animal,swim,bybirth).
edge(human,swim,mustlearn).
path(X,Y) :- edge(X,isa,Y).
path(X,Y) :- edge(X,isa,Z), path(Z,Y).
swim(X,Y) :- edge(X,swim,Y).
swim(X,Y) :- path(X,Z), swim(Z,Y).
Now, to use the above knowledge base, I use the following:
?- swim(simba,bybirth).
?- swim(simba,mustlearn).
And for both the queries, Prolog returns true. I want Prolog to check for the property swim locally first, then look at the direct parent, and so on in a hierarchical fashion. And it should stop searching as soon as we know that Simba "mustlearn" to swim, and shouldn't look any further. Thus, it should return false for the first query and true for the second.
I know it has to be done by limiting backtracking. I tried using the cut and not operators, but couldn't succeed. Is there a way to achieve this?
I tried it and ran into a problem too. I thought this might work:
swim(X,Y) :- once((edge(X,swim,Y); path(X,Z), swim(Z,Y))).
It doesn't work, because if Y is already instantiated on the way in, the first step will fail to unify and it will try the second route going through the human intermediate. So even though the query only produces one result, it can be fooled into producing swim(simba, bybirth). The solution is to force Prolog to commit to a binding on another variable and then check that binding after the commitment:
swim(X,Y) :-
once((edge(X,swim,Method); path(X,Z), swim(Z,Method))),
Method = Y.
This tells Prolog, there is only one way to get to this method, so find that method, and then it must be Y. If you find the wrong method, it won't go on a search, it will just fail. Try it!
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.
diverso([X|L1],L2) :- nonp(X,L2), diverso(L1,L2).
nonp(X,[]).
nonp(X,[A|B]) :- X\=A, nonp(X,B).
this is my code, it doesn't work and I don't know why.
Error is
Diverso/2 unknown predicate
My query is:
?-diverso([3,4],[1,2]).
Adding the recursive base case for the diverso predicate solves the problem!
I'm having some troubles in understanding the following prolog predicate ,
I can understand that it concatenate some chars , also produces the possible lists (first & second goal ) , but I can't understand how it do this ? how it executes ?
domains
i=integer
l=i*
slist=string*
clist=char*
predicates
nondeterm conc(clist,clist,clist).
clauses
conc([],L,L).
conc([H|L1],L2,[H|L3]):-
conc(L1,L2,L3).
The first goal
goal
conc(['a','b'],['c','d'],L).
result
L=['a','b','c','d']
the second goal
goal
conc(L1,L2,['a','b','c']).
result
L1=[], L2=['a','b','c']
L1=['a'], L2=['b','c']
L1=['a','b'], L2=['c']
L1=['a','b','c'], L2=[]
4 Solutions
I'm neither an expert in prolog, nor in logic, but I'll try to explain what I think how it works.
After the call to:
<- conc(['a','b'],['c','d'],L).
Prolog will look for a predicate that matches the signature. In this case that would be:
conc([H|L1],L2,[H|L3])
It tries to resolve the variables with the given data.
|1: H:=['a'], L1:=['b'], L2:=['c','d']
Now it steps into the recursion with these data calling:
<- conc(['b'], ['c','d'], L3).
|2: H:=['b'], L1:=[], L2:=['c','d']
<- conc([], ['c','d'], L3).
The last line causes prolog to use the predicate with the signature:
conc([],L,L).
resolving:
|3: L:=['c','d']
Now Prolog is able to construct the concatinated List handing over L up the recursion stack.
|2: [H|L3]:=['b','c','d']
|1: [H|L3]:=['a','b','c','d']
I hope that is a hint in the right direction. Maybe you should read this article for clarification
I am just starting to use Prolog, and already I've run into problem with a seemingly simple example. Here is my .pl file:
hacker(P) :- mountaindew(P), doesntsleep(P).
hacker(P) :- writesgoodcode(P).
writesgoodcode(jeff).
Then, after I load the program into swipl, I test it with this line at the prompt
writesgoodcode(jeff).
I thought it would display true, but I get this error:
?- hacker(jeff).
ERROR: hacker/1: Undefined procedure: mountaindew/1
Exception: (7) hacker(jeff) ?
This program works fine, but this doesn't solve my problems:
hacker(P) :- writesgoodcode(P).
writesgoodcode(jeff).
$ swipl -s dumb.pl
% dumb.pl compiled 0.00 sec, 1,112 bytes
?- hacker(jeff).
true.
Can anyone explain why my original program doesn't work? From my understanding, Prolog should "skip" the first statement since it doesn't have enough information, and check the next line. It does have enough info for that second line, and thus it should evaluate true. Any help or a point in the right direction would be great. Thanks.
As the error message says, you have an undefined procedure mountaindew/1. To make your code return true, your options are:
Define this predicate
Declare that this predicate is dynamic: dynamic(mountaindew/1)
Declare that all unknown predicates should fail (not recommended): set_prolog_flag(unknown, fail)
you could also change the order of the predicates (cannot be done always ofc)
but mostly what Kaarel said.
in the end there is not really a point in writing something that will always fail, even if you are still developing the code
This works but as I am a beginner I can't say why. The word "uninstantiated" may apply. Despite not knowing why it works, I think it's helpful to show one way that works.
hacker(P) :- mountaindew(P), doesntsleep(P).
hacker(P) :- writesgoodcode(P).
mountaindew(john).
doesntsleep(john).
writesgoodcode(jeff).