Is anyone aware of a built-in or any other way that will only make prolog go to the next clause when input from the terminal is given?
So for instance, the one giving the query will have to hit the y button
to go the next clause after the query has been matched.
This is the so-called vanilla meta-interpreter (I cribbed from this answer by Jan Burse):
solve(true) :- !.
solve((A,B)) :- !, solve(A), solve(B).
solve(H) :- clause(H,B), solve(B).
You can extend this to await some input by adding a predicate to ask for input before continuing:
confirm :- write('Continue? [y/n] '), flush_output, get_char(y).
Now replace the second clause with this:
solve((A,B)) :- !, solve(A), confirm, solve(B).
Edit: I asked how to add built-ins and got a response that you could just add this clause:
solve(T) :- call(T).
Related
I'm using swipl but working the adventure tuorial from Amzi!. The syntax difference is causing me a headache. After setting up the facts, I have these statements
list_things(Place) :-
location(X, Place),
tab(2),
write(X), nl,
false.
list_connections(Place) :-
connect(Place, X),
tab(2),
write(X), nl,
false.
look :-
here(Place),
write('You are in the '), write(Place), nl,
write("You can go to: "), nl,
list_connections(Place), nl,
write('You can see: '), nl,
list_things(Place).
When I run look., it only outputs the first list from list_connections. That is
?- look.
You are in the kitchen
You can go to:
office
cellar
dining room
false.
Now, I understand the false at the end of the function is terminating the look, but I don't know the correct syntax in swipl.
Now, I understand the false at the end of the function is terminating the look
The false at the end of list_connections(Place) forces it to backtrack and retry, writing all the connected places as it does so. Once it has got through them all and failed for the last time, I think there is supposed to be another rule for it:
list_connections(_).
I see it here in Amzi! chapter 5:
That rule is a "succeed for anything" rule which will allow look to carry on and then list_things can run. And there is a similar one for list_things.
I decided to start playing with Prolog (SWI-Prolog). I wrote a program, and now I'm trying to write a simple main predicate so that I can create a .exe and run the program from the command line. That way, I can find true/false relationships from the command line rather than from the prolog GUI. However, I am having trouble understanding what actually goes in the main predicate. Here is the program so far:
mother(tim, anna).
mother(anna, fanny).
mother(daniel, fanny).
mother(celine, gertrude).
father(tim, bernd).
father(anna, ephraim).
father(daniel, ephraim).
father(celine, daniel).
parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
First Try:
I put all of the relationship definitions in a predicate called family_func().Then, I tried to call that function from main by typing main. into the command line. I expected to be able to start finding relationships like I did before I created the predicates, but instead, the program started with this error:
ERROR: c:/.../ancestor.pl:18:0: Syntax error: Operator expected
Here is the code:
family_func():-
mother(tim, anna).
...
parent(X,Y) :- mother(X,Y).
...
main:-
family_func().
Second Try:
I tried putting all of the definitions in the main predicate. I expected to be able to type main. and then have the program pause and wait for me to start entering clauses (almost like in Java where you run a program and it waits for user input). Instead, when I typed main., it returned false.
Question 1:
I am used to writing code in Java. So, in my mind, The first thing I tried should work. I basically defined local variables in family_func() and then I called smaller "methods" (i.e. parent(X,Y) :- mother(X,Y).) that should find the relationships between those variables. When I call main, at the very least, I would have expected the program to wait for me to enter the relationship, return the result, and then close. Why doesn't this work?
Question 2:
How would I actually write a main predicate? Are there any good examples for a program like this? I've tried the example here, but couldn't get it to work.
Thanks for any help.
Edit:
New Attempt - main. returns false, and running parent(tim, anna). right after running main. returns false even though it should be true.
:- dynamic mother/2.
:- dynamic father/2.
family_func:-
assert(mother(tim, anna)).
assert(father(tim, bernd)).
parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
main:-
family_func.
Edit:
Just in case anyone else needs to know, as #CapelliC states in the comments under the answer, there needs to be a comma between calls. For example:
family_func:-
assert(mother(tim, anna)),
assert(mother(anna, fanny)),
assert(mother(daniel, fanny)),
assert(mother(celine, gertrude)),
assert(father(tim, bernd)),
assert(father(anna, ephraim)),
assert(father(daniel, ephraim)),
assert(father(celine, daniel)).
I think should be (no empty argument list allowed)
:- dynamic mother/2.
... other dynamically defined relations...
family_func:-
assert(mother(tim, anna)).
...
% rules can be dynamic as well, it depends on your application flow...
parent(X,Y) :- mother(X,Y).
...
main:-
family_func.
How do I get only one output from a SWI-Prolog query? I have tried using cut (!) but it does not seem to work.
For example:
I already filled my knowledge base up with statements and I wanted to find any one name who is both female and is the mother of someone.
I have already tried:
mother(X,Y), female(X).
...but that gives me all of the X-__ and Y-__
I have also tried:
mother(X,Y), female(X), !.
... but that still gives me both the X-__ and Y__
I only want to find the X. Does anyone have any tips for me to somehow only get one?
?- setof(t, Y^ ( mother(X, Y), female(Y) ), _).
which will remove duplicates (redundant answers/solutions), too. Or using library(lambda):
?- X+\ ( mother(X, Y), female(Y) ).
which does not remove redundant answers.
I want to have a prolog program which can auto run once I compile finish and it should read input from user keyboard. However when i use
:- write('Your name is: '), nl, read(X).
there is not any effect on read(X), which it means that there us not any prompt for users to key in. Is there any solution for this problem? My prolog compiler is WIN-Prolog 5.0, thanks for your helo :)
maybe you need something like
:- initialization(main). % changed to be ISO compliant, was :- initialization main.
main :- write('Your name is: '), nl, read(X).
at least, ISO Prologs do it in this way....
Since read/1 is meant to parse Prolog (it's a full fledged parser), you must supply a Prolog term, and don't forget, as Joel76 suggested, to complete input with a dot: for instance:
Your name is:
|: 'Carlo'.
I've been trying to loop through a list and writing it to a file, why is the following not working?
loop_through_list(List) :-
member(Element, List),
write(Element),
write(' '),
fail.
write_list_to_file(Filename,List) :-
tell(Filename), % open file to be written
loop_through_list(List),
told. % flush buffer
First, why it fails :
You use fail to provoke backtracking, which can be a good technique, but not there. Because it will make your predicate false in the end, when member has ran out of solutions. Then, once loop_through_list is false, told isn't reached and the writing isn't made properly (when I test it, the file is created but nothing is written).
If you use :
loop_through_list([]).
loop_through_list([Head|Tail]) :-
write(Head),
write(' '),
loop_through_list(Tail).
instead, it works.
But, even with this code working, you might want to use
open(Filename, write, Stream), write(Stream, Element) and close(Stream) instead of tell and told for the reasons explained in the link at the bottom of this answer.
For example :
loop_through_list(_File, []) :- !.
loop_through_list(File, [Head|Tail]) :-
write(File, Head),
write(File, ' '),
loop_through_list(File, Tail).
write_list_to_file(Filename,List) :-
open(Filename, write, File),
loop_through_list(File, List),
close(File).
or
loop_through_list(File, List) :-
member(Element, List),
write(File, Element),
write(File, ' '),
fail.
write_list_to_file(Filename,List) :-
open(Filename, write, File),
\+ loop_through_list(File, List),
close(File).
using your code and joel76 trick.
See Prolog how to save file in an existing file
It covers the same matter.
I fail to see the reason to do use this method to write a list to a file.
Programming in prolog should generally not involve loops;
besides, this is not a loop structure, it's more like a hack (or even abuse).
(and just like your case leads to unexpected bugs and problems)
Just use recursion and print the elements of the list:
write_list([]).
write_list([H|T]):-
write(H),
write(' '),
write_list(T).
more elegant and could be more efficient too.
other than that, using open/4 etc (ISO IO) instead of tell/1 etc (Edinburgh IO) is generally better; check false's post
predicate loop_through_list(List), always fails, so to succed you just have to write \+loop_through_list(List),