Prolog if-elseif-else - prolog

As the question says, thats kind of what i wanna simulate in prolog. So i'm making a game,here's some code:
move(X):-
get_char(Y)
get_char(_),
get_char(Z),
not(OldLoc='Z'),
not(NewLoc = 'Z'),
validmove(OldLoc,NewLoc).
move(_):-
write('Thanks for playing!'), nl.
move(X):-
write('Invalid move!'), nl,
write('Try Again?'), nl,
move(X).
what i want to do is if the first predicate check fails at not(OldLoc='Z'),not(NewLoc = 'Z'), then go to the next predicate move(_) and it fails at validmove(OldLoc,NewLoc) then go to the next move(X). I'm very new to prolog and i'm almost completely clueless.

If-then-else:
http://www.swi-prolog.org/pldoc/doc_for?object=send_arrow/2
Another if-then-else:
http://www.swi-prolog.org/pldoc/doc_for?object=(*-%3E)/2
Sample #1:
?- test = test -> print('TRUTH') ; print('FALSE').
TRUTH
Sample #2:
?- test = test -> (test2 = test3 -> print('TRUTH'); print('FALSE2')); print('FALSE').
FALSE2

Related

Using attribute_goal/2 the right way in SICStus Prolog

I'm writing a "solver" using the SICStus Prolog attributed variables interface:
:- module(attach2, [attach2/2]).
:- use_module(library(atts)).
:- attribute att/2.
attach2(X,Y) :- put_atts(X,att(X,Y)),
put_atts(Y,att(Y,X)).
verify_attribute(_,_,[]).
attribute_goal(V,(true,G,true,G,true)) :- get_atts(V,att(X,Y)), G = attach2(X,Y).
Sample query:
| ?- attach2(X,Y), copy_term(X,Xc,Xcc), copy_term(Y,Yc,Ycc), copy_term(X+Y,XYc,XYcc).
Xcc = attach2:(true,attach2(Xc,_A),true,attach2(Xc,_A),true),
Ycc = attach2:(true,attach2(Yc,_B),true,attach2(Yc,_B),true),
XYc = _C+_D,
XYcc = (attach2:attach2(_C,_D),attach2:attach2(_D,_C)),
attach2(X,Y),
attach2(Y,X) ? ;
no
If I change attribute_goal/2 to ...
attach2(X,Y) :- put_atts(X,att(X,Y)),
put_atts(Y,att(X,Y)).
... the answer get better:
| ?- attach2(X,Y), copy_term(X,Xc,Xcc), copy_term(Y,Yc,Ycc), copy_term(X+Y,XYc,XYcc).
Xcc = attach2:(true,attach2(Xc,_A),true,attach2(Xc,_A),true),
Ycc = attach2:(true,attach2(_B,Yc),true,attach2(_B,Yc),true),
XYc = _C+_D,
XYcc = attach2:attach2(_C,_D),
attach2(X,Y) ? ;
no
My conclusion from this:
copy_term/3 collects goals from attribute_goal/2 and if it encounters more than one attributed variable, then it removes trivial true and duplicate goals.
It this essentially right?

Prolog Procedure si(A) Does not Exist

This is the code
verificar(S) :-
(si(S)
->
true ;
(no(S)
->
fail ;
preguntar(S))).
preguntar(Pregunta) :-
write('Tiene los siguientes sintomas: '),
write(Pregunta),
write('?'),
read(Respuesta),
nl,
( (Respuesta == si)
->
assert(si(Pregunta));
assert(no(Pregunta)), fail).
and the problem is
procedure `si(A)' does not exist
Reachable from:
verificar(A)
resfriado
hipotesis(A)
evaluar
The problem is for the first run, the program does not know what you mean with si(A) since there is no predicate or rule defined. Quickfix: Add dummy data like
si(nothing).
no(nothing).
which can be removed after the first "valid" entry in your knowledge base.
You have not written the predicate for si(). This is why you are getting the error:-
procedure `si(A)' does not exist

How to allow program to proceed?

How to make the program proceed to menu1/0 after false appear
mylist([a,b,c]).
myprog(X) :- mylist(L), member(X, L).
go :- start_message,menu1.
start_message :-
write('This is a program.'),nl,
write('Below are a list:'),nl,
myprog(X),
write(X),nl,
fail.
menu1 :-
nl,write('Select operation:'),nl,
write('1. Input time'),nl,
write('2. Exit program'),nl.
Below is what I am stuck with:
go.
This is a program.
Below are a list:
a
b
c
false
You can do like this
start_message :-
write('This is a program.'),nl,
write('Below are a list:'),nl,
( myprog(X),
write(X),nl,
fail
; true ).
Now when myprog/1 cannot succeed anymore, control goes to true/0 and start_message/0 succeeds.
Remove the fail statement in the last line of start_message.

Prolog Query Exercise - Beginner

I'm a begginer at Prolog and I need some help with this exercise, this is the knowledge base provided:
album(‘R. Stevie Moore’, ‘Manuscription’).
album(‘Lane Steinberg’, ‘Manuscription’).
album(‘R. Stevie Moore’, ‘The Yung & Moore Show’).
album(‘Yukio Yung’, ‘The Yung & Moore Show’).
album(‘Jessie Evans’, ‘Autonervous’).
album(‘Bettina Koster’, ‘Autonervous’).
album(‘Lucia Pamela’, ‘Walkin on the moon’).
album(‘Shooby Taylor’, ‘The Human Horn’).
album(‘Tiny Tim’, ‘God Bless Tiny Tim’).
album(‘The Legendary Stardust Cowboy’, ‘Rock-It to Stardom’).
vinil(‘Rock-It to Stardom’).
vinil(‘Walking on the Moon’).
cd( ‘God Bless Tiny Tim’).
cd(‘Walking on the Moon’).
cd(‘Autonervous’).
cd(‘Manuscription’).
cassette(‘The Human Horn’).
cassette(‘The Yung & Moore Show’).
mp3(‘Walkin on the Moon’).
I need to make a query that will return to me all the albums that were made by only one musician.
Thanks for your help :)
In the comments you have provided your code album(X,B),album(Y,C), B \= C. Actually, this is not too far away from a correct solution.
A correct solution could be:
one_musician_album(X) :-
album(A, X),
\+ (album(B, X), A \= B).
The meaning of the predicate is: an album X is a "one-musician album" if this album is authored by some musician A and it's not possible to find a different musician B authored the album X.
Test run:
?- one_musician_album(X).
X = 'Walkin on the moon' ;
X = 'The Human Horn' ;
X = 'God Bless Tiny Tim' ;
X = 'Rock-It to Stardom'.
To get all answers you have to type ';' after each answer.
Maybe this is not needed for you, but it's possible to get all answers in a list with findall:
?- findall(X, one_musician_album(X), Albums).
Albums = ['Walkin on the moon', 'The Human Horn', 'God Bless Tiny Tim', 'Rock-It to Stardom'].
Here is a generalization, based on 'all solutions' builtin bagof/3.
Note that
?- bagof(A, album(A,T), As).
T = 'Autonervous',
As = ['Jessie Evans', 'Bettina Koster'] ;
T = 'God Bless Tiny Tim',
As = ['Tiny Tim']
....
then, restricting the authors (As) to be a list of a single element, we get albums with a single author
?- bagof(A, album(A,T), [A]).
A = 'Tiny Tim',
T = 'God Bless Tiny Tim' ;
...
then, we could use findall/3, as in the good answer by Sergey, or, again, bagof/3, with explicit quantification:
?- bagof(T, A^bagof(A, album(A, T), [A]), Ts).
Ts = ['God Bless Tiny Tim', 'Rock-It to Stardom', 'The Human Horn', 'Walkin on the moon'].

Debugging in SWI-prolog - unbound variables

Consider the following Prolog code. It edits lines of a particular type in its input and prints out the remaining lines w/o any change. It uses a DCG called rule which isn't included below, since it's not important to the question.
go:-
prompt(_, ''),
processInput.
processInput:-
read_line_to_codes(current_input, Codes),
processInput(Codes).
processInput(Codes):-
(Codes \= end_of_file
->
(phrase(rule(Part1, Part2), Codes)
->
format('~s - ~s\n', [ Part1, Part2 ])
;
format('~s\n', [ Codes ])),
processInput
;
true).
:- go, halt.
This works fine. However, suppose I change processInput/1 to the following, it just says that Warning: /home/asfernan/tmp/tmp.pl:28: Goal (directive) failed: user: (go,halt).
processInput(Codes):-
(Codes \= end_of_file
->
(\+phrase(rule(Part1, Part2), Codes)
->
format('~s\n', [ Codes ]))
;
format('~s - ~s\n', [ Part1, Part2 ]),
processInput
;
true).
The if & else parts of the phrase(rule(Part1, Part2), Codes) DCG match have been exchanged. This is obviously a newbie mistake, but the fact that go, halt failed isn't very helpful. What can I do to make the error message indicate that the failure was because Part1 & Part2 were not bound in the format('~s - ~s\n', [ Part1, Part2 ]) line? I was able to track down this error because the code is small, but I may not have been able to do so had the code been big.
In Prolog the following is not the same:
..., ( Cond -> Then ; Else ), ...
and
..., ( \+ Cond -> Else ; Then ), ...
In general, a goal \+ Cond will never instantiate its variables. So you
have to stick to the original formulation.
In case you are interested to process entire
files with DCGs, consider SWI's library(pio).

Resources