Replacing prolog base case with recursive call












4















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.










share|improve this question





























    4















    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.










    share|improve this question



























      4












      4








      4








      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.










      share|improve this question
















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Feb 9 at 9:14









      repeat

      16.2k443139




      16.2k443139










      asked Nov 16 '18 at 9:55









      Kareem AboughazalaKareem Aboughazala

      1301112




      1301112
























          3 Answers
          3






          active

          oldest

          votes


















          1














          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



          enter image description here



          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).


          enter image description here



          This will start a second screen with the graphical debugger.



          enter image description here



          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.



          enter image description here



          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






          share|improve this answer
























          • Beware of of people asking question and then deleting question and answer.

            – Guy Coder
            Nov 19 '18 at 0:22



















          5














          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.






          share|improve this answer































            3














            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.






            share|improve this answer


























              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
              });


              }
              });














              draft saved

              draft discarded


















              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









              1














              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



              enter image description here



              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).


              enter image description here



              This will start a second screen with the graphical debugger.



              enter image description here



              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.



              enter image description here



              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






              share|improve this answer
























              • Beware of of people asking question and then deleting question and answer.

                – Guy Coder
                Nov 19 '18 at 0:22
















              1














              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



              enter image description here



              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).


              enter image description here



              This will start a second screen with the graphical debugger.



              enter image description here



              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.



              enter image description here



              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






              share|improve this answer
























              • Beware of of people asking question and then deleting question and answer.

                – Guy Coder
                Nov 19 '18 at 0:22














              1












              1








              1







              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



              enter image description here



              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).


              enter image description here



              This will start a second screen with the graphical debugger.



              enter image description here



              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.



              enter image description here



              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






              share|improve this answer













              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



              enter image description here



              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).


              enter image description here



              This will start a second screen with the graphical debugger.



              enter image description here



              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.



              enter image description here



              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







              share|improve this answer












              share|improve this answer



              share|improve this answer










              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



















              • 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













              5














              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.






              share|improve this answer




























                5














                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.






                share|improve this answer


























                  5












                  5








                  5







                  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.






                  share|improve this answer













                  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.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 16 '18 at 11:49









                  matmat

                  37k33059




                  37k33059























                      3














                      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.






                      share|improve this answer






























                        3














                        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.






                        share|improve this answer




























                          3












                          3








                          3







                          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.






                          share|improve this answer















                          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.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Nov 16 '18 at 12:06

























                          answered Nov 16 '18 at 11:53









                          tastas

                          7,5022820




                          7,5022820






























                              draft saved

                              draft discarded




















































                              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.




                              draft saved


                              draft discarded














                              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





















































                              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







                              Popular posts from this blog

                              Xamarin.iOS Cant Deploy on Iphone

                              Glorious Revolution

                              Dulmage-Mendelsohn matrix decomposition in Python