Writing recursion in swi-prolog

Tag: prolog , swi-prolog Author: wuwenxian11 Date: 2012-08-31

I have successfully connected PHP with Prolog and managed to query the desired knowledge base that resides in knowledge_base.pl file and managed to echo the results via php exec function.

I encountered a problem in echoing the true/false value that Prolog returns after each query execution (see previous question) so I came up with a solution that I have trouble implementing.

Let's assume I have a simple knowledge_base.pl file with these facts and rules:


likes(erin, reading).
likes(john, reading).

hangs_out_with(erin, X) :-
    likes(X, reading),
    writeln('Someone s got a new friend!!').

Lets say that I want to see if erin is a girl and if so, write that it is true, or else write that it is false. I added this to my knowledge_base.pl file:

girl(erin) :-
     -> write('it is true')
     ;  write('it is not true'). 

When I enter the query: ?- girl(erin). I get an out of local stack error. I searched the Web and found out that this is due to infinite recursion.

Can someone give me a hint in how to write

girl(X) :-
    (    girl(X)
      -> write('it is true')
      ;  write('it is not true')).  

in Prolog? Thanks in advance.

As a new user I'm not allowed to post pictures.

SWI-Prolog's output:

1 ?-hangs_out_with(erin,kosta).

2 ?-hangs_out_with(erin,john).
Someone s got a new friend!!

Command prompt's output:

C:\(directory)>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,kosta),halt.
1 ?-halt. (the halt is inputted by me.)
C:\(directory)>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,john),halt.
Someone s got a new friend!!

The first query fails and the second succeds. As you can see, prolog after the query executions outputs true/false but when i execute the same query in command prompt the true/false values do not get echoed!!

I thought it'll be likes(erin, reading). likes(john, erin). :) just kidding. :) ... joel76 is right - you can't use the same name for the new predicate. This is what causes the runaway recursion and hence out of local stack error. You already have a predicate named girl, it defines a fact girl(erin) in your database. Now you define new predicate, report_whether_it_is_a_girl(X):- girl(X) -> write('IS A GIRL') ; write('IS NOT'). Just using a different name for a different predicate is enough, and it makes sense to. One succeeds or fails ; the other writes a message.
@WillNess thanks. I 've already tried out what joel76 suggested. As you can see in the question i asked, I m doing these as to echo the true/false value that prolog returns but for some reason does not get echoed when i execute a query trough windows command prompt.
I've added an answer. If this doesn't help, please edit your question and show us a transcript of what's going on.
this seems to be related. :)
@WillNess :) yes it is related! :) thanks ONCE again. You are the best!! :)

Best Answer

so you "connect PHP to Prolog" by executing a Prolog query in command shell and capturing and analyzing its output. http://www.swi-prolog.org/man/quickstart.html says

" Starting SWI-Prolog on Unix

By default, SWI-Prolog is installed as 'swipl'. The command-line arguments of SWI-Prolog itself and its utility programs are documented using standard Unix man pages."

So do consult a man page about "-q" switch. Is it the "-q" for quiet perhaps? What does "-f" mean (ok, that's probably "file")? But the solution is the same - just use a different name for the new predicate.

Notice that in your first attempt,

C:>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,kosta),halt.
1 ?-halt. (the halt is inputted by me.)

halt isn't executed, precisely because hangs_out_with(erin,kosta) has failed. A comma signifies conjunction (an "and").

All you need to do is create a new predicate that reports whether the goal is true or false, and succeeds always:

  hangs_out_with(A,B)- > writeln(['YES',A,B]) ; writeln('NO').

and use it instead:

C:>swipl -q -f knowledge_database.pl -g report_hangs_out_with(erin,kosta),halt.

Also, Prolog echoing "true" or "false" is part of its interactive session. But you terminate it with halt!

edit: you posted:

1 ?-hangs_out_with(erin,kosta).

So, when you run that query in interactive Prolog shell, it reports the failure. halt/0 exits the Prolog shell. When you run it with a goal specified through command line switch, apparently it does not report the success of failure. That's the fact of nature as far as we users are concerned (a.o.t. the compiler writers). It is easily addressable with what I've shown you. And you yourself say that it works, too. For each predicate that can fail or succeed, define another, reporting predicate, just as I've shown you.

Here's a sample transcript (in Windows, but that's irrelevant). That should clear up your doubts:

C:\Program Files\pl\bin>plcon -q -g (writeln('****'),halt).
****                          // didn't say Yes, right??

C:\Program Files\pl\bin>plcon -q
1 ?- writeln('****'),halt.
****                          // didn't say Yes here either

C:\Program Files\pl\bin>plcon -q
1 ?- writeln('****').

Yes                           // does say Yes as part of interaction
2 ?- halt.

C:\Program Files\pl\bin>      

So that's the way it is. Deal with it. :) Or write Jan and ask him to change it. :)


Hey Will Ness :) The -q is for quiet. It is to supress Prolog's welcome message. If the hangs_out_with(erin,kosta) had failed then it would say so when i ran the exact query in prolog, but it didn't. The halt is to let prolog know that i won't be inputting another query. If I ommit it then it echoes 1?- and waits for a query. Please do try it yourselfe and see that the output is exactly what I described above. I know that what you suggest is working but please feel free to visit my previous question link I have in my initial post. Check my last comment and see the problem that occurs..
@Erin I've edited my answer with the response. Check it out. :)
well my friend I did write Jan!!! :). Once again thanks for your effort. I did think of think of creating a predicate for echoing the true/false values I needed but i wanted to use recursion, but you and joel76 told me that wasn't a good idea. Anyway thanks for help. :)
@Erin you're welcome! :) Please accept one of the answers, the one that you feel has helped you (the most). You'll get +2 rep. :) (press the big empty V-shaped outline next to that answer). When you have 15 rep, you'll be able to up-vote answers too. :) About recursion - recursion is good, left recursion (the one that does not terminate) is BAD. :) Happy trails!

Other Answer1

I think you should ask

is_girl(X) :-
    girl(X) -> write('t is true') ; write('it is not true'). 


Do you mean this kind of thing ?

is_type(Type, X) :-
    call(Type, X) -> writeln(yes); writeln(no).


Hey joel76. Although this works perfectly I think that it can be a bit "tiresome". What I mean is that I have to write 5 new rules to see if the the given facts and rules are true or false. Can that be done recursively?
Hey again joel76! I was looking for a way to recrsively define the predicates in my knowledge base. something like: girl(G):-girl(G)-> write('it is true'); write('it is not true'). boy(B):-boy(B)->write('it is true'); write('it is not true'). likes(P, S):-likes(P, S)->write('it is true'); write('it is not true'). hangs_out_with(G, B) :- hangs_out_with(G, B))->write('it is true'); write('it is not true'). well something like that. Is wrong to use recusion to achieve what i want? Thanks for trying to help me.
You can't do that, you will get always stack overflow ! You call the same predicate each time so you can't use recursion. In Prolog you must have facts e.g; girl(barbara). girl(emma). ... and rules, different of facts, wich use facts to succeed or fail. Did you try what i suggest ?
yes i tried what you suggested and it works. The thing is that what i really want is to echo the true/false value that Prolog returns after each query execution . For some reason when i execute prolog from the windows command line, the true/false value doesn't get echo. If there's a writeln command it gets perfectly executed but the true/false that I also need doesn't. Do you know why?
Because is_type always succeeds. You can try is_type(Type, X) :- call(Type, X) -> writeln(yes); writeln(no), fail. but I don't think it's a good idea.

Other Answer2

girl(erin) :-
     -> write('it is true')
     ;  write('it is not true'). 

This is wrong for two reasons. Prolog tries to resolve the body taking the left-most literal. So it basically goes in a loop "is erin girl? yes, if erin is girl. Is erin girl?..."

The second reason is you are mixing two different things. Try to keep your knowledge representation part separated from the way you use it. In Prolog you just say:


And then query

?- girl(erin)

Prolog will just say "yes". If you want to print it, probably the easiest way is adding a predicate.

check_and_print(X) :- X, write(X), write(" is true").

Probably you need a call(X) instead of X, depending on the implementation you are using.

I'm not sure about the command prompt out, I suspect the outcome is returned in a different way.


... a meta predicate! :)