Reputation: 25
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?
Upvotes: 1
Views: 314
Reputation: 22803
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!
Upvotes: 0