Prolog predicate with multiple lists - prolog

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.

Related

Prolog Start clauses only after input

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

Prolog read predicate cant read user key in in initialization?

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

How to get both drive predicates working in prolog?

begin:-
go,
initialise. % drive predicate
begin:-
write('Sorry cannot help'),nl,nl.
go:-
write('Below is the list of the current toys available within the
store.'),nl,nl,nl,nl,
loop_through_list([car, football, action_men, train_tracks, lego, football, bikes, control_car, drees_up, doll, bear, furbies, craft, doll_house]).
loop_through_list([Head|Tail]) :-
write(Head),
write(' '),
loop_through_list(Tail).
initialise:-
nl,nl,nl,nl,
tab(40),write('******************************************'),nl,
tab(40),write('*** TOY GENERATING SYSTEM ***'),nl,
tab(40),write('******************************************'),nl,nl,
write('Please answer the following questions'),
write(' y (yes) or n (no).'),nl,nl, nl, nl.
The problem here is that the go:- and the initialise:- work separately when on their own, but not when put together. Is there a problem with all the nls?
The problem is that go/0 doesn't work corrently. While it prints the list, it fails at the end, meaning that the execution will stop afterwards. Therefore, when you run begin/0, initialize/0 will never run.
To fix it you need to add a base case for loop_through_list/0:
loop_through_list([]).
loop_through_list([Head|Tail]) :-
write(Head),
write(' '),
loop_through_list(Tail).
As a side note, "print_list" would be a more descriptive name for loop_through_list/0

Undefined procedure in SWI-Prolog

Ok i got these two predicated hangman and graphics
fail([]).
hangman:-
getPhrase(Ans),
!,
write('Welcome to hangman.'),
nl,
fail(FailedList),
graphics(FailedList), %<--- The call is made here.
name(Ans,AnsList),
makeBlanks(AnsList, BlankList),
getGuess(AnsList,BlankList, FailedList).
graphics(FailedList):-
length(FailedList, L),
L == 0,
write('-----------'), nl,
write('|'), nl,
write('|'), nl,
write('|'), nl,
write('|'), nl,
write('|'), nl,
write('|'), nl,
write('|'), nl,
write('|'), nl,
write('/\'), nl.
Why do i get the error: ERROR: hangman/0: Undefined procedure: graphics/1?
Note that if i put the predicate graphics inside hangman in comments my program works fine.
(this answer is not really about the question asked so please let the answer to #SeçkinSavaşçı who did a great job answering the question, it's more of a code review)
Here, you visibly want to test if a list is empty and react accordingly by displaying some things. For the test if a list is empty part, you're doing it wrong:
graphics(FailedList):-
length(FailedList, L),
L == 0,
% some IO stuff
In prolog, you can use unification in a more straightforward manner:
graphics(FailedList):-
length(FailedList, 0),
% some IO stuff
or, better, where you directly test for the empty list in the head as a condition to execute the body of the predicate:
graphics([]):-
% some IO stuff
For the IO part, you're doing it kinda wrong again. SWI-Prolog, for example, has a writeln/1 predicate, that would make your code lighter:
graphics([]):-
writeln('-----------'),
writeln('|'),
writeln('|'),
writeln('|'),
writeln('|'),
writeln('|'),
writeln('|'),
writeln('|'),
writeln('|'),
writeln('/\\').
Still better, the format/1 predicate could be used:
graphics([]):-
format('-----------~n|~18~n|~n|~n|~n|~n|~n|~n|~n/\\').
The main predicate seems to have some problems too, but I'll let you look into it and ask questions if you're stuck somewhere :)
write('/\'), nl.
In the last line, you are escaping the ending quotation mark with \'. Change it to:
write('/\\'), nl.
BTW: #Mog has written the answer before I had a look at the comments, I tested it and now it finds graphics/1.

User input in prolog

I want to write a program that sets cold to true if the user enters winter and sets warm to true if the user enters summer. This is what I have so far:
start :- write('What season is it?: '), read(X), season(X).
cold :- season(winter).
warm :- season(summer).
However when I query start and enter winter for the season I get an error that season/1 is undefined. To fix this I tried changing my code to the following:
start :- season(X).
season(X) :- write('What season is it?: '), read(X).
cold :- season(winter).
warm :- season(summer).
Now when I query start it asks for the season as expected and I entered winter. I queried cold expecting a return of true since I figured season(winter) would be true, but instead I was again prompted to answer "what season is it?". How can I make this simple program work?
It looks that what you want to do is kind of "forward chaining". So you
want to be able to add a fact to the knowledge base, and then see
additional facts pop up.
Such things were very fashionable in the 80's when expert systems emerged
and can also be done with Prolog. Here is an article roughly describing the
difference between "backward chaining" and "forward chaining":
Logic Programming Associates Ltd.
ProWeb: Expert System
I have tried to remodel something similar to the above forward chaining
via the clause expansion mechanism that is available in many Prolog
systems and via an agenda that is held in the knowledge base as ordinary
facts. The expansion mechanism changes a rule of the following form:
P :- A
Into a rule where X is a fresh variable not occuring in P or A:
delta(X, P) :- A_new(X)
Where A_new is a condition that says that P is new when a new fact
X has arrived. Lets consider your example:
?- ['delta.p'].
?- [user].
:- forward season/1.
:- forward cold/0.
:- forward warm/0.
cold :- season(winter).
warm :- season(summer).
^D
These two Prolog rules would be turned into the following delta/2 rules
via the rewriting. Since the rules are very simple, the delta/2 rules
are also very simple:
?- listing(delta/2).
delta(X, cold) :-
X = season(winter).
delta(X, warm) :-
X = season(summer).
Here is an example session:
?- list.
Yes
?- volunteer(season(winter)).
Yes
?- list.
season(winter).
cold.
Yes
The rewriting in delta.p is very primitive. The rewriting can be enhanced
to support rigid predicates and to support the dynamic removal of facts.
Possible additional application areas of the "forward chaining" are then:
Natural Language Processing
Constraint Solving
Best Regards
The current delta/2 rewriting after a few more years development:
http://www.jekejeke.ch/idatab/doclet/blog/en/docs/15_min/02_reference/minimal/delta.html
An Article showing that a Constraint Store can be modelled:
https://plus.google.com/+JekejekeCh/posts/8oHErwopKxK
P.S.: The predicate name volunteer/1 stems form Nexpert Object,
an expert system shell in use in the 80's and 90's.
NEXPERT OBJECT version 3.0, Jean-Marie Chauvet, Neuron Data, Inc.
P.P.S.: But you might want to lookup newer things, such as Rete-NT, or OWL:
http://answers.semanticweb.com/questions/3304/forward-vs-backward-chaining
Because "cold/0" and "warm/0" take no arguments, it is impossible to change the result at runtime without altering their definition at runtime. The simplest way to do this is just to add or remove the facts "cold." and "warm." depending on user input, using assert/1 and retractall/1.
start :- write('What season is it?: '), read(X), season(X).
season(summer) :- retractall(cold), assert(warm).
season(winter) :- retractall(warm), assert(cold).
While defining the facts, you need to change the syntax a little bit.
start(Y) :- write('What season is it?: '), read(X), nl, season(X,Y).
season(winter,cold).
season(summer,warm).
Note that the user needs to end the input with a full stop. (eg. winter.)
season(winter,cold).
season(summer,warm).
start:-write('What season is it?'),write(' '),read(X),season(X,Y),write(Y).
The output will be look like this:
?- start.
What season is it? winter.
cold
true.

Resources