Replacing prolog base case with recursive call
I am new to Prolog, started learning it recently using the awesome book Learn Prolog Now!. There is something I don't fully understand and it's really bugging me. One of the exercises questions is
We have the following knowledge base and predicate:
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :- child(X,Y).
descend(X,Y) :- child(X,Z),
descend(Z,Y).
What would happen if we change the predicate to the following:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
I know that this would cause an infinite recursion on false cases, I can't fully understand why though.
If I understand correctly, in the first case above if a false query is given child(X,Z)
would exhaust all its options trying to unify multiple elements to Z then fail, backtrack to the previous X then try option for Z again that would satisfy child(X, Z). (Please correct me if I'm wrong).
I am not sure why the same won't happen though for the second definition of the descend predicate.
recursion prolog
add a comment |
I am new to Prolog, started learning it recently using the awesome book Learn Prolog Now!. There is something I don't fully understand and it's really bugging me. One of the exercises questions is
We have the following knowledge base and predicate:
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :- child(X,Y).
descend(X,Y) :- child(X,Z),
descend(Z,Y).
What would happen if we change the predicate to the following:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
I know that this would cause an infinite recursion on false cases, I can't fully understand why though.
If I understand correctly, in the first case above if a false query is given child(X,Z)
would exhaust all its options trying to unify multiple elements to Z then fail, backtrack to the previous X then try option for Z again that would satisfy child(X, Z). (Please correct me if I'm wrong).
I am not sure why the same won't happen though for the second definition of the descend predicate.
recursion prolog
add a comment |
I am new to Prolog, started learning it recently using the awesome book Learn Prolog Now!. There is something I don't fully understand and it's really bugging me. One of the exercises questions is
We have the following knowledge base and predicate:
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :- child(X,Y).
descend(X,Y) :- child(X,Z),
descend(Z,Y).
What would happen if we change the predicate to the following:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
I know that this would cause an infinite recursion on false cases, I can't fully understand why though.
If I understand correctly, in the first case above if a false query is given child(X,Z)
would exhaust all its options trying to unify multiple elements to Z then fail, backtrack to the previous X then try option for Z again that would satisfy child(X, Z). (Please correct me if I'm wrong).
I am not sure why the same won't happen though for the second definition of the descend predicate.
recursion prolog
I am new to Prolog, started learning it recently using the awesome book Learn Prolog Now!. There is something I don't fully understand and it's really bugging me. One of the exercises questions is
We have the following knowledge base and predicate:
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :- child(X,Y).
descend(X,Y) :- child(X,Z),
descend(Z,Y).
What would happen if we change the predicate to the following:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
I know that this would cause an infinite recursion on false cases, I can't fully understand why though.
If I understand correctly, in the first case above if a false query is given child(X,Z)
would exhaust all its options trying to unify multiple elements to Z then fail, backtrack to the previous X then try option for Z again that would satisfy child(X, Z). (Please correct me if I'm wrong).
I am not sure why the same won't happen though for the second definition of the descend predicate.
recursion prolog
recursion prolog
edited Feb 9 at 9:14
repeat
16.2k443139
16.2k443139
asked Nov 16 '18 at 9:55
Kareem AboughazalaKareem Aboughazala
1301112
1301112
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
The easier way to help you instead of writing a long and detailed explanation here that is just reproducing the run of a trace step by step is to just suggest that you use the graphical trace built into SWI-Prolog and do the stepping yourself.
Before showing you that one change you should make to the code is to rename the predicate for the second example so you have both of them available at the same time.
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :-
child(X,Y).
descend(X,Y) :-
child(X,Z),
descend(Z,Y).
descend_2(X,Y) :-
child(X,Y).
descend_2(X,Y) :-
descend_2(X,Z),
descend_2(Z,Y).
Start up SWI-Prolog
Load up your source code. I personally use consult/1 e.g.
consult("C:/Users/Eric/Documents/Projects/Prolog/SO_question_100.pl").
Turn on the graphical tracer with gtrace/0
gtrace.
Enter your query, e.g.
descend_2(anne,bridget).
This will start a second screen with the graphical debugger.
At this point I would have to give a long explanation of how to use the graphical debugger and what all of the different items in the display means but here is one part that is of note. I reached it by just pressing the space a few times to single step. Continue this until you hear a chime. When you hear the chime it means you need to switch to the other screen and give input, in this case just press space bar to accept the answer. Then switch back to the screen with the graphical debugger and continue to press the space bar to single step.
The part of interest is the stack on the right. I put a green box around one of them that shows a Y
like icon, which represents a choice point. If you keep doing the space bar you will notice that the stack keeps growing with more choice points.
So what is happening is that you code has a choice but the choice is not getting resolved. Take a look at left recursion and Prolog/Recursive Rules
Beware of of people asking question and then deleting question and answer.
– Guy Coder
Nov 19 '18 at 0:22
add a comment |
Let's take a moment to reduce the snippet you show to a fragment that clearly shows a reason for the nontermination.
The initial fragment is the whole program you posted:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
Now, we insert false/0
at some places. For example:
descend(X,Y) :- false, child(X,Y).
descend(X,Y) :- descend(X,Z),
false,
descend(Z,Y).
I am using strikeout text to indicate parts of the program that have no influence on termination. That is, we actually end up with:
descend(X,Y) :- descend(X,Z).
This fragment alone already causes nontermination. No pure clause you add to this, and nothing that follows the single goal can prevent it! Hence, to make this terminating, you must change this fragment.
See failure-slice for more information.
add a comment |
For illustration purposes, let's consider the pair (a,b)
since it is not covered by your facts child/2. If you issue the query...
?- descend(a,b).
... Prolog will try the first clause of descend/2, with the substitutions X=a
and Y=b
:
descend(a,b) :- child(a,b).
... and fail, since the goal child(a,b)
fails. Then Prolog moves on to the second clause of descend/2:
descend(a,b) :-
... where a new variable Z
is introduced and descend/2 is called recursively:
descend(a,b) :- descend(a,Z),
Prolog now tries the first clause of descend/2...
descend(a,Z) :- child(a,Z).
... and fails, because the goal child(a,Z)
fails. So Prolog tries the second clause of descend/2:
descend(a,Z) :-
... where a new variable, let's call it Z2 (depending on the Prolog-system you are using it will be a name like _G3325
(SWI), _A (YAP)
, ... but for this example let's stick with the more illustrative Z2) is introduced and the recursive goal is called:
descend(a,Z) :- child(a,Z2).
Since there's always a new variable that can be introduced, the above definition of descend/2 will loop until you run out of stack. With similar reasoning you can comprehend why the queries...
?- descend(anne,bridget).
true ;
ERROR: Out of local stack
?- descend(X,Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = donna,
Y = emily ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
X = anne,
Y = emily ;
ERROR: Out of local stack
... loop as well after producing answers.
EDIT:
See @mat's excellent answer for a much more elegant way to identify the fragment, that causes non-termination.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53335339%2freplacing-prolog-base-case-with-recursive-call%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
The easier way to help you instead of writing a long and detailed explanation here that is just reproducing the run of a trace step by step is to just suggest that you use the graphical trace built into SWI-Prolog and do the stepping yourself.
Before showing you that one change you should make to the code is to rename the predicate for the second example so you have both of them available at the same time.
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :-
child(X,Y).
descend(X,Y) :-
child(X,Z),
descend(Z,Y).
descend_2(X,Y) :-
child(X,Y).
descend_2(X,Y) :-
descend_2(X,Z),
descend_2(Z,Y).
Start up SWI-Prolog
Load up your source code. I personally use consult/1 e.g.
consult("C:/Users/Eric/Documents/Projects/Prolog/SO_question_100.pl").
Turn on the graphical tracer with gtrace/0
gtrace.
Enter your query, e.g.
descend_2(anne,bridget).
This will start a second screen with the graphical debugger.
At this point I would have to give a long explanation of how to use the graphical debugger and what all of the different items in the display means but here is one part that is of note. I reached it by just pressing the space a few times to single step. Continue this until you hear a chime. When you hear the chime it means you need to switch to the other screen and give input, in this case just press space bar to accept the answer. Then switch back to the screen with the graphical debugger and continue to press the space bar to single step.
The part of interest is the stack on the right. I put a green box around one of them that shows a Y
like icon, which represents a choice point. If you keep doing the space bar you will notice that the stack keeps growing with more choice points.
So what is happening is that you code has a choice but the choice is not getting resolved. Take a look at left recursion and Prolog/Recursive Rules
Beware of of people asking question and then deleting question and answer.
– Guy Coder
Nov 19 '18 at 0:22
add a comment |
The easier way to help you instead of writing a long and detailed explanation here that is just reproducing the run of a trace step by step is to just suggest that you use the graphical trace built into SWI-Prolog and do the stepping yourself.
Before showing you that one change you should make to the code is to rename the predicate for the second example so you have both of them available at the same time.
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :-
child(X,Y).
descend(X,Y) :-
child(X,Z),
descend(Z,Y).
descend_2(X,Y) :-
child(X,Y).
descend_2(X,Y) :-
descend_2(X,Z),
descend_2(Z,Y).
Start up SWI-Prolog
Load up your source code. I personally use consult/1 e.g.
consult("C:/Users/Eric/Documents/Projects/Prolog/SO_question_100.pl").
Turn on the graphical tracer with gtrace/0
gtrace.
Enter your query, e.g.
descend_2(anne,bridget).
This will start a second screen with the graphical debugger.
At this point I would have to give a long explanation of how to use the graphical debugger and what all of the different items in the display means but here is one part that is of note. I reached it by just pressing the space a few times to single step. Continue this until you hear a chime. When you hear the chime it means you need to switch to the other screen and give input, in this case just press space bar to accept the answer. Then switch back to the screen with the graphical debugger and continue to press the space bar to single step.
The part of interest is the stack on the right. I put a green box around one of them that shows a Y
like icon, which represents a choice point. If you keep doing the space bar you will notice that the stack keeps growing with more choice points.
So what is happening is that you code has a choice but the choice is not getting resolved. Take a look at left recursion and Prolog/Recursive Rules
Beware of of people asking question and then deleting question and answer.
– Guy Coder
Nov 19 '18 at 0:22
add a comment |
The easier way to help you instead of writing a long and detailed explanation here that is just reproducing the run of a trace step by step is to just suggest that you use the graphical trace built into SWI-Prolog and do the stepping yourself.
Before showing you that one change you should make to the code is to rename the predicate for the second example so you have both of them available at the same time.
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :-
child(X,Y).
descend(X,Y) :-
child(X,Z),
descend(Z,Y).
descend_2(X,Y) :-
child(X,Y).
descend_2(X,Y) :-
descend_2(X,Z),
descend_2(Z,Y).
Start up SWI-Prolog
Load up your source code. I personally use consult/1 e.g.
consult("C:/Users/Eric/Documents/Projects/Prolog/SO_question_100.pl").
Turn on the graphical tracer with gtrace/0
gtrace.
Enter your query, e.g.
descend_2(anne,bridget).
This will start a second screen with the graphical debugger.
At this point I would have to give a long explanation of how to use the graphical debugger and what all of the different items in the display means but here is one part that is of note. I reached it by just pressing the space a few times to single step. Continue this until you hear a chime. When you hear the chime it means you need to switch to the other screen and give input, in this case just press space bar to accept the answer. Then switch back to the screen with the graphical debugger and continue to press the space bar to single step.
The part of interest is the stack on the right. I put a green box around one of them that shows a Y
like icon, which represents a choice point. If you keep doing the space bar you will notice that the stack keeps growing with more choice points.
So what is happening is that you code has a choice but the choice is not getting resolved. Take a look at left recursion and Prolog/Recursive Rules
The easier way to help you instead of writing a long and detailed explanation here that is just reproducing the run of a trace step by step is to just suggest that you use the graphical trace built into SWI-Prolog and do the stepping yourself.
Before showing you that one change you should make to the code is to rename the predicate for the second example so you have both of them available at the same time.
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :-
child(X,Y).
descend(X,Y) :-
child(X,Z),
descend(Z,Y).
descend_2(X,Y) :-
child(X,Y).
descend_2(X,Y) :-
descend_2(X,Z),
descend_2(Z,Y).
Start up SWI-Prolog
Load up your source code. I personally use consult/1 e.g.
consult("C:/Users/Eric/Documents/Projects/Prolog/SO_question_100.pl").
Turn on the graphical tracer with gtrace/0
gtrace.
Enter your query, e.g.
descend_2(anne,bridget).
This will start a second screen with the graphical debugger.
At this point I would have to give a long explanation of how to use the graphical debugger and what all of the different items in the display means but here is one part that is of note. I reached it by just pressing the space a few times to single step. Continue this until you hear a chime. When you hear the chime it means you need to switch to the other screen and give input, in this case just press space bar to accept the answer. Then switch back to the screen with the graphical debugger and continue to press the space bar to single step.
The part of interest is the stack on the right. I put a green box around one of them that shows a Y
like icon, which represents a choice point. If you keep doing the space bar you will notice that the stack keeps growing with more choice points.
So what is happening is that you code has a choice but the choice is not getting resolved. Take a look at left recursion and Prolog/Recursive Rules
answered Nov 16 '18 at 11:35
Guy CoderGuy Coder
16.2k44287
16.2k44287
Beware of of people asking question and then deleting question and answer.
– Guy Coder
Nov 19 '18 at 0:22
add a comment |
Beware of of people asking question and then deleting question and answer.
– Guy Coder
Nov 19 '18 at 0:22
Beware of of people asking question and then deleting question and answer.
– Guy Coder
Nov 19 '18 at 0:22
Beware of of people asking question and then deleting question and answer.
– Guy Coder
Nov 19 '18 at 0:22
add a comment |
Let's take a moment to reduce the snippet you show to a fragment that clearly shows a reason for the nontermination.
The initial fragment is the whole program you posted:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
Now, we insert false/0
at some places. For example:
descend(X,Y) :- false, child(X,Y).
descend(X,Y) :- descend(X,Z),
false,
descend(Z,Y).
I am using strikeout text to indicate parts of the program that have no influence on termination. That is, we actually end up with:
descend(X,Y) :- descend(X,Z).
This fragment alone already causes nontermination. No pure clause you add to this, and nothing that follows the single goal can prevent it! Hence, to make this terminating, you must change this fragment.
See failure-slice for more information.
add a comment |
Let's take a moment to reduce the snippet you show to a fragment that clearly shows a reason for the nontermination.
The initial fragment is the whole program you posted:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
Now, we insert false/0
at some places. For example:
descend(X,Y) :- false, child(X,Y).
descend(X,Y) :- descend(X,Z),
false,
descend(Z,Y).
I am using strikeout text to indicate parts of the program that have no influence on termination. That is, we actually end up with:
descend(X,Y) :- descend(X,Z).
This fragment alone already causes nontermination. No pure clause you add to this, and nothing that follows the single goal can prevent it! Hence, to make this terminating, you must change this fragment.
See failure-slice for more information.
add a comment |
Let's take a moment to reduce the snippet you show to a fragment that clearly shows a reason for the nontermination.
The initial fragment is the whole program you posted:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
Now, we insert false/0
at some places. For example:
descend(X,Y) :- false, child(X,Y).
descend(X,Y) :- descend(X,Z),
false,
descend(Z,Y).
I am using strikeout text to indicate parts of the program that have no influence on termination. That is, we actually end up with:
descend(X,Y) :- descend(X,Z).
This fragment alone already causes nontermination. No pure clause you add to this, and nothing that follows the single goal can prevent it! Hence, to make this terminating, you must change this fragment.
See failure-slice for more information.
Let's take a moment to reduce the snippet you show to a fragment that clearly shows a reason for the nontermination.
The initial fragment is the whole program you posted:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z),
descend(Z,Y).
Now, we insert false/0
at some places. For example:
descend(X,Y) :- false, child(X,Y).
descend(X,Y) :- descend(X,Z),
false,
descend(Z,Y).
I am using strikeout text to indicate parts of the program that have no influence on termination. That is, we actually end up with:
descend(X,Y) :- descend(X,Z).
This fragment alone already causes nontermination. No pure clause you add to this, and nothing that follows the single goal can prevent it! Hence, to make this terminating, you must change this fragment.
See failure-slice for more information.
answered Nov 16 '18 at 11:49
matmat
37k33059
37k33059
add a comment |
add a comment |
For illustration purposes, let's consider the pair (a,b)
since it is not covered by your facts child/2. If you issue the query...
?- descend(a,b).
... Prolog will try the first clause of descend/2, with the substitutions X=a
and Y=b
:
descend(a,b) :- child(a,b).
... and fail, since the goal child(a,b)
fails. Then Prolog moves on to the second clause of descend/2:
descend(a,b) :-
... where a new variable Z
is introduced and descend/2 is called recursively:
descend(a,b) :- descend(a,Z),
Prolog now tries the first clause of descend/2...
descend(a,Z) :- child(a,Z).
... and fails, because the goal child(a,Z)
fails. So Prolog tries the second clause of descend/2:
descend(a,Z) :-
... where a new variable, let's call it Z2 (depending on the Prolog-system you are using it will be a name like _G3325
(SWI), _A (YAP)
, ... but for this example let's stick with the more illustrative Z2) is introduced and the recursive goal is called:
descend(a,Z) :- child(a,Z2).
Since there's always a new variable that can be introduced, the above definition of descend/2 will loop until you run out of stack. With similar reasoning you can comprehend why the queries...
?- descend(anne,bridget).
true ;
ERROR: Out of local stack
?- descend(X,Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = donna,
Y = emily ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
X = anne,
Y = emily ;
ERROR: Out of local stack
... loop as well after producing answers.
EDIT:
See @mat's excellent answer for a much more elegant way to identify the fragment, that causes non-termination.
add a comment |
For illustration purposes, let's consider the pair (a,b)
since it is not covered by your facts child/2. If you issue the query...
?- descend(a,b).
... Prolog will try the first clause of descend/2, with the substitutions X=a
and Y=b
:
descend(a,b) :- child(a,b).
... and fail, since the goal child(a,b)
fails. Then Prolog moves on to the second clause of descend/2:
descend(a,b) :-
... where a new variable Z
is introduced and descend/2 is called recursively:
descend(a,b) :- descend(a,Z),
Prolog now tries the first clause of descend/2...
descend(a,Z) :- child(a,Z).
... and fails, because the goal child(a,Z)
fails. So Prolog tries the second clause of descend/2:
descend(a,Z) :-
... where a new variable, let's call it Z2 (depending on the Prolog-system you are using it will be a name like _G3325
(SWI), _A (YAP)
, ... but for this example let's stick with the more illustrative Z2) is introduced and the recursive goal is called:
descend(a,Z) :- child(a,Z2).
Since there's always a new variable that can be introduced, the above definition of descend/2 will loop until you run out of stack. With similar reasoning you can comprehend why the queries...
?- descend(anne,bridget).
true ;
ERROR: Out of local stack
?- descend(X,Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = donna,
Y = emily ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
X = anne,
Y = emily ;
ERROR: Out of local stack
... loop as well after producing answers.
EDIT:
See @mat's excellent answer for a much more elegant way to identify the fragment, that causes non-termination.
add a comment |
For illustration purposes, let's consider the pair (a,b)
since it is not covered by your facts child/2. If you issue the query...
?- descend(a,b).
... Prolog will try the first clause of descend/2, with the substitutions X=a
and Y=b
:
descend(a,b) :- child(a,b).
... and fail, since the goal child(a,b)
fails. Then Prolog moves on to the second clause of descend/2:
descend(a,b) :-
... where a new variable Z
is introduced and descend/2 is called recursively:
descend(a,b) :- descend(a,Z),
Prolog now tries the first clause of descend/2...
descend(a,Z) :- child(a,Z).
... and fails, because the goal child(a,Z)
fails. So Prolog tries the second clause of descend/2:
descend(a,Z) :-
... where a new variable, let's call it Z2 (depending on the Prolog-system you are using it will be a name like _G3325
(SWI), _A (YAP)
, ... but for this example let's stick with the more illustrative Z2) is introduced and the recursive goal is called:
descend(a,Z) :- child(a,Z2).
Since there's always a new variable that can be introduced, the above definition of descend/2 will loop until you run out of stack. With similar reasoning you can comprehend why the queries...
?- descend(anne,bridget).
true ;
ERROR: Out of local stack
?- descend(X,Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = donna,
Y = emily ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
X = anne,
Y = emily ;
ERROR: Out of local stack
... loop as well after producing answers.
EDIT:
See @mat's excellent answer for a much more elegant way to identify the fragment, that causes non-termination.
For illustration purposes, let's consider the pair (a,b)
since it is not covered by your facts child/2. If you issue the query...
?- descend(a,b).
... Prolog will try the first clause of descend/2, with the substitutions X=a
and Y=b
:
descend(a,b) :- child(a,b).
... and fail, since the goal child(a,b)
fails. Then Prolog moves on to the second clause of descend/2:
descend(a,b) :-
... where a new variable Z
is introduced and descend/2 is called recursively:
descend(a,b) :- descend(a,Z),
Prolog now tries the first clause of descend/2...
descend(a,Z) :- child(a,Z).
... and fails, because the goal child(a,Z)
fails. So Prolog tries the second clause of descend/2:
descend(a,Z) :-
... where a new variable, let's call it Z2 (depending on the Prolog-system you are using it will be a name like _G3325
(SWI), _A (YAP)
, ... but for this example let's stick with the more illustrative Z2) is introduced and the recursive goal is called:
descend(a,Z) :- child(a,Z2).
Since there's always a new variable that can be introduced, the above definition of descend/2 will loop until you run out of stack. With similar reasoning you can comprehend why the queries...
?- descend(anne,bridget).
true ;
ERROR: Out of local stack
?- descend(X,Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = donna,
Y = emily ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
X = anne,
Y = emily ;
ERROR: Out of local stack
... loop as well after producing answers.
EDIT:
See @mat's excellent answer for a much more elegant way to identify the fragment, that causes non-termination.
edited Nov 16 '18 at 12:06
answered Nov 16 '18 at 11:53
tastas
7,5022820
7,5022820
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53335339%2freplacing-prolog-base-case-with-recursive-call%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown