How to read an array "list" & print it in prolog? - prolog

How to read an array "list" & print it in prolog ?
I need to :-
Prompt user to insert an array
The user some how tells me that He's finished
Then I print it
I just can't think of how to make this in a predicate.

Is this what you would like to have?
1 ?- p(X).
|: a.
|: b.
|: c.
|: d.
|: end.
Code:-
X = [a, b, c, d].
This is how one can implement this behaviour:
p(X) :- read(A), q(A,X-[]).
q(end,X-X) :- !.
q(A,[A|X]-Y) :- read(B), q(B,X-Y).

Related

change the output in Prolog - for detecting covid symptoms

I would like to ask if you could advise me how to create a condition or redo the code. I need the output of the program to detect the symptoms of covid19. If I mark 'yes' at least 3 times out of ten symptoms in the program, the output will be 'you have covid19 symptoms'. If 'yes' less than 3 times, the output will be 'you have no covid19 symptoms'.
Thank you
start :- x(Disease), write('the verdict is : '), write(Disease),nl, undo.
x(symptoms) :- symptoms,!.
x(withoutsymptoms). /* without symptoms */
symptoms :- verify(conjunctivitis),
verify(sore_throat),
verify(fatigure),
verify(shake),
verify(diarrhea),
verify(runny_nose),
verify(cold),
verify(muscle_pain),
verify(chest_pressure),
verify(loss_of_taste),
verify(fever).
ask(Question) :-
write('How are you? '),
write(Question),
write('? '),
read(Response),
nl,
( (Response == yes ; Response == yes)
->
assert(yes(Question)) ;
assert(no(Question)), fail).
:- dynamic yes/1,no/1.
verify(S) :-
(yes(S)
->
true ;
(no(S)
->
fail ;
ask(S))).
undo :- retract(yes(_)),fail.
undo :- retract(no(_)),fail.
undo.
That attempt looks confusing. How about the following, which additionally doesn't use assertz/1 to poke the Prolog database, but collects the responses in a list for later analysis.
Also, instead of using the "term deserializer" read/1, we use read_line_to_string/2
% ---
% Symptoms are listed naturally in a list.
% There are 11 symptoms
symptoms( [conjunctivitis,
sore_throat,
fatigue,
shake,
diarrhea,
runny_nose,
cold,
muscle_pain,
chest_pressure,
loss_of_taste,
fever] ).
% ---
% Go through the symptoms list, collecting answers
ask_about_symptoms([],[]).
ask_about_symptoms([Symptom|MoreSymptoms],[Answer-Symptom|MorePairs]) :-
repeat,
format("Do you have: ~s?\n",[Symptom]),
read_line_to_string(user_input,S1),
string_lower(S1,S2),
(
member(S2,["yes","y","ja","oui"])
->
Answer = yes
;
member(S2,["no","n","nein","non"])
->
Answer = no
;
format("Please try again\n",[]),fail % Back to "repeat"
),
ask_about_symptoms(MoreSymptoms,MorePairs).
is_yes_pair(yes-_).
ask_candidate :-
symptoms(Symptoms),
ask_about_symptoms(Symptoms,AnswerPairs),
!, % don't go back to asking
include(is_yes_pair,AnswerPairs,Included),
format("So you say you have the following symptoms: ~q~n",[Included]),
length(Included,Hits),
((Hits>=3) -> format("Looks bad.~n",[]) ; format("You probably don't have it.~n",[])).
Example run:
?- [rona].
true.
?- ask_candidate.
Do you have: conjunctivitis?
|: y
Do you have: sore_throat?
|: y
Do you have: fatigue?
|: n
Do you have: shake?
|: n
Do you have: diarrhea?
|: n
Do you have: runny_nose?
|: y
Do you have: cold?
|: foo
Please try again
Do you have: cold?
|: bar
Please try again
Do you have: cold?
|: n
Do you have: muscle_pain?
|: n
Do you have: chest_pressure?
|: y
Do you have: loss_of_taste?
|: y
Do you have: fever?
|: y
So you say you have the following symptoms: [yes-conjunctivitis,yes-sore_throat,yes-runny_nose,yes-chest_pressure,yes-loss_of_taste,yes-fever]
Looks bad.
true.

Prolog: I keep getting errors when trying to compile a simple program

I'm trying to make a simple grammar parser that checks whether a specific sentence pattern is valid or not. the grammar rules are as follows:
terminals: circleplus, circleor, 1, 0
non-terminals: S; T
start symbol: S
production rules: S --> S circleplus T | S circleor T | T, and: T --> 0 | 1
sentence([]).
sentence([a, b, c|Tail]) :- checkHead(a), checkC(b), checkT(c), sentenceCheck(Tail).
sentenceCheck([]).
sentenceCheck([b, c|Tail]) :- checkC(b), checkT(c), sentenceCheck(Tail).
checkT(c) :- T(c).
checkC(b) :- C(b).
checkHead(a) :- Head(a).
C(circleor).
C(circleplus).
Head(0).
Head(1).
T(0).
T (1).
% ?- sentence ([[0 , circleor ,1] , circleplus ,1]) .
% ==> true
The bottom comments are what a sample input --> output would look like.
Appreciate any help.
EDIT: (per response to my question)
sentence([]).
sentence([A, B, C|Tail]) :- checkHead(A), checkC(B), checkT(C), sentenceCheck(Tail).
sentenceCheck([]).
sentenceCheck([B, C|Tail]) :- checkC(B), checkT(C), sentenceCheck(Tail).
checkT(C) :- t(C).
checkC(B) :- c(B).
checkHead(A) :- head(A).
c(circleor).
c(circleplus).
head(0).
head(1).
t(0).
t(1).
Only now the query sentence([0, circleor, 1]). returns false when it should be true. Any ideas?
In prolog variables start with a capital letter and constant terms start with a lowercase letter. You are getting the error because prolog expects the predicate to be a constant term rather than a variable.
sentence([]).
sentence([A, B, C|Tail]) :- checkHead(A), checkC(B), checkT(C), sentenceCheck(Tail).
sentenceCheck([]).
sentenceCheck([B, C|Tail]) :- checkC(B), checkT(C), sentenceCheck(Tail).
checkT(C) :- t(C).
checkC(B) :- c(B).
checkHead(A) :- head(A).
c(circleor).
c(circleplus).
head(0).
head(1).
t(0).
t(1).
The above changes will help but your sample input, output will not work as you are nesting the list. If you do not nest the list as follows it will work.
?- sentence([0, circleor, 1, circleplus, 1]).
true.
A solution even when the input is not flattened is :
sentence(A) :- t(A).
sentence([A, B, C]) :-
sentence(A),
c(B),
t(C).
c(circleor).
c(circleplus).
t(0).
t(1).

Append to list if specific word is entered

I am trying to append a list and a word together, and if the user types a specific word I want to add a certain letter to the list.
For example, I want to make the words entered in a list change based on the pronoun.
?- append([t,a,l,k], she, X).
X = [t, a, l, k, s].
so if the user enters [t, a, l, k] and she, Prolog will add 's' to the end of the list.
The code I have so far is only able to append the two entered values and not based on if the user enters a certain word.
append( [], X, X).
append( [A | B], C, [A | D]) :- append( B, C, D).
result:
?- append([t,a,l,k], she, X).
X = [t, a, l, k|she].
How can I make it so if they type she prolog adds 's' to the list instead of 'she'?
Thank you.
You have to decompose the atom she into individual characters first.
It is also best to use my_append/3 because append/3 already exists.
my_append( [], W, [F]) :- atom_chars(W,[F|_]).
my_append( [A | B], W, [A | D]) :- my_append(B, W, D).
:- begin_tests(shemanator).
test("append 'she'", true(X == [t, a, l, k, s])) :-
my_append([t,a,l,k], she, X).
test("append 'she' to an empty list", true(X == [s])) :-
my_append([], she, X).
test("append 's'", true(X == [t, a, l, k, s])) :-
my_append([t,a,l,k], s, X).
:- end_tests(shemanator).
And so
?- run_tests.
% PL-Unit: shemanator ... done
% All 3 tests passed
true.

Prolog reasoning about predicates

Assume someone wrote the following huge list of clauses:
loves(me, wife).
loves(me, dog).
loves(wife, dog).
hates(me, enemy).
attracts(iron, magnet).
...
Now I want to automatically generate reciprocal clauses given some higher-order predicate and rule similar to:
reciprocal([loves, hates, attracts, ...]).
some_conclusion :- some_premises.
so that I have the following expected result:
?- loves(wife, me).
true.
To keep things simple, I ignored the list argument and instead defined the simple clause reciprocal(loves). with some complex rule using reciprocal(X), but I can't seem to assert a rule with success.
I've tried different variations and orderings of
assert(
Y :- (reciprocal(P), Y =.. [P, B, A], X =.. [P, A, B], call(X))
).
or (to add the deduced clauses themselves)
assert(Y), reciprocal(P), Y =.. [P, B, A], X =.. [P, A, B], call(X)
but I've only got false or errors like Arguments are not sufficiently instantiated using SWI-Prolog.
My question is (obviously): how can I make this rule work? I don't care whether the rule is part of the database or just a preprocessor to add the actual clauses to the database (although the former would be preferable), I just want to learn how to reason about predicates (i.e. how to use higher-order predicates).
Note: I've learned logic programming since a month only, and I want to try out some ideas from Notation3 and N-triples etc.
EDIT:
The missing part, the absolute cherry on the cake, is some dynamic solution using a rule similar to
Y :- (reciprocal(P), call(P, A, B), Y =.. [P, B, A]).
If anyone has some solution for this one, please post it!
I found the way to add clauses one by one to the database as such (MVP):
?- [user].
|: loves(me, wife).
|: loves(me, dog).
|: loves(wife, dog).
|: reciprocal(loves).
|: (Ctrl-Z)
?- dynamic loves/2 %! seems necessary for next clause...
true.
?- reciprocal(P), X =.. [P, A, B], Y =.. [P, B, A], assert(X :- (Y, !)).
P = loves,
X = loves(A, B),
Y = loves(B, A).
?- loves(wife, me).
true.
It seems I didn't arrange the 'rule' in this way which is procedurally sound.
Now I'll focus on findall to avoid requiring user input (the ; after each solution for P).
EDIT:
I completed all but one feature... Given a file db.pl containing
loves(me, wife).
loves(me, dog).
loves(wife, dog).
attracts(iron, magnets).
and a file rules.pl containing
reciprocal([
loves,
attracts
]).
parse_reciprocal([]).
parse_reciprocal([H|T]) :-
X =.. [H, A, B], Y =.. [H, B, A], dynamic(H/2), assert(X :- (Y, !)),
parse_reciprocal(T).
:- initialization reciprocal(L), parse_reciprocal(L).
I succeed at my first goal
?- [db].
true.
?- [rules].
true.
?- loves(dog, wife).
true.
?- attracts(magnets, iron).
true.
The missing part, the absolute cherry on the cake, is some dynamic solution using a rule similar to
Y :- (reciprocal(P), call(P, A, B), Y =.. [P, B, A]).

Prolog , Append with no repititions

Hey I'm trying to append two list with no "double" members
for example
A = [a, b, c]
B = [x, c, q]
then ->
append2(A,B,P)
P= [a,b,c,x,q]
I write this code, but it doesn't work...
not_member(_, []).
not_member(X, [Y|Ys]) :- X \= Y, not_member(X, Ys).
append2(A, [], A).
append2([], A, A).
append2([h1|ls], B, [h1|P]) :- not_member(h1, B), !, append2(ls, B, P).
append2([h1|ls], B, P) :- member(h1, P), append2(ls, B, P).
Thanks for helping :)
Assuming there are no variables in your input lists, but allowing duplicates in each list you may write:
append2(A,B,C):-
findall(Item, append2_item(A,B,Item), C).
append2_item(A,_,ItemA):-
append(HeadA, [ItemA|_], A),
\+ member(ItemA, HeadA).
append2_item(A,B,ItemB):-
append(HeadB, [ItemB|_], B),
\+ member(ItemB, HeadB),
\+ member(ItemB, A).
First clause of append2_item/3 selects (ordered) distinct items from the first list. Second clause of append2_item/3 selects (ordered) distinct items from the second list which are not present in the first list.
append2/3 just collects those elements.
Test case:
?- append2([a,b,c,a],[x,c,q,x],C).
C = [a, b, c, x, q].
Check out the pure code in my answer
to the related question "intersection and union of 2 lists"!
Telling from your requirements, predicate list_list_union/3 is just what you are looking for:
?- list_list_union([a,b,c],[x,c,q],Ls).
Ls = [a,b,c,x,q]. % succeeds deterministically
list_list_union/3 is monotone, so we get sound answers
even when using non-ground terms:
?- As = [_,_,_], Bs = [_,_,_], list_list_union(As,Bs,Ls), As = [a,b,c], Bs = [x,c,q].
As = [a,b,c], Bs = [x,c,q], Ls = [a,b,c,x,q] ; % logically sound result
false.

Resources