Prolog: Adding elements to list through read/1 - list

I am trying to add user input to a list with add_read_list/2 until the word "end." is encountered. This is how the output is supposed to look:
add_read_list(Resultlist, [a,b]).
|: c.
|: d.
|: e.
|: f.
|: end.
Resultlist = [f,e,d,c,a,b].
This is how far I have come:
add_read_list(Resultlist,Entrylist) :-
read(end), append([], Entrylist, Resultlist).
add_read_list(Resultlist, Entrylist) :-
read(Input), append([Input], Entrylist, X),
add_read_list(Resultlist, X).
But this way every second input gets skipped:
add_read_list(Resultlist, [a,b]).
|: c.
|: d.
|: e.
|: f.
|: end.
Resultlist = [f,d,a,b].
What am I doing wrong?

drop the first clause, and use the simple 'if/then/else' construct:
add_read_list(Resultlist, Entrylist) :-
read(Input),
( Input = end
-> reverse(Resultlist, Entrylist)
; add_read_list(Resultlist, [Input|Entrylist])
).
instead of appending each item read, 'cons' it, and reverse the full list when done (well, simply unify to get the list in LIFO, as seems required. i.e. instead of reverse(Resultlist, Entrylist), Resultlist = Entrylist)

The actual error is read(end). This will only succeed, if the term read in is end. Otherwise it fails.
But I do have a lot of reservation to tell you this at all, since nobody every does this is Prolog. Here are the actual things that would need improvement.
The first, is to use end_of_file in place of end, because this is automatically generated at the end of a file, plus you can write it yourself, too.
The second is the way how to handle this. You need to read and then process the term read in:
... read(X), ( X == end_of_file -> ... ; /* whatever */ ... ), ....
However, please do reconsider your entire task. There is a single reason why this could be needed: When you are processing a Prolog file. But this you get cheaper and less error prone by saying [file].
So better design your data to fit into Prolog terms.

Related

How to check if a certain pattern exists in a list in prolog

i was trying to implement a prolog predict that checks if a certain pattern say (x,m) exists in a list or m exists at the very end of the list and count the number of its occurrence i never get an answer to the number of times the pattern existed.why?
my attempt was :
certainP([_,m],RESULT,W):-
W is RESULT+1.
certainP([x,m|T],START,RESULT):-
RESULT is START+1,
START is RESULT,
certainP(T,START,RESULT).
This should do what you describe:
certainP([],N,N).
certainP([_],N,N).
certainP([x,m|T],N,N2) :-
N1 is N+1,
certainP(T,N1,N2).
certainP([_|T],N,N2) :-
certainP(T,N,N2).
This assumes that the middle argument is provided an initial numeric value in the query.

Prolog find element in list of lists with preference

I have list of lists like:
L = [[Q,w,E,],[Q,w,Z,r],[A,s,D,f]]
I know the first two and I need to get the rest.
For example I have Q,w and I need to get Z,r or E,r.
I would like to somehow tell that with priority I always want that touple contain Z, but if doesnt exist give me E,r.
I tried:
member([Q,w,Z,VB],[[Q,w,E,o],[Q,w,Z,r],[A,s,D,f]]).
But that always give me Z = E, VB = o
First you need to know the difference in Prolog between an Atom and a Variable, you can read about their syntax here
Now, if you want a list of atoms that begin with an upper-case letter, you must enclose them in single quotes, otherwise prolog will interpret them as variables.
Now if you fix the syntax of your consult, you will get the following result:
?- member(['Q',w,Z,VB],[['Q',w,'E',o],['Q',w,'Z',r],['A',s,'D',f]]).
VB = o,
Z = 'E'
VB = r,
Z = 'Z'
false
Note how in this case I enclosed in single quote all atoms beginning with an upper-case letter, except for Z and VB in the first argument of the member/2 predicate, cause in this case they function as variables to be instanciated by prolog with the atoms needed to complete this case.

write elements in a list in prolog

I am learning prolog. How do you write elements in a list in prolog where the list may contains elements beginning with a capital letter.
for example: I have the predicate my_write/1
my_write([]). /* Base case: An empty list */
my_write([X|R]):- write(X),nl,my_write(R). /* Recursive case: */
But when I run my_write([How, are, you]). I get [_G749,are,you]
I know that words that begin with capital letter are variables in prolog.
I know you could enclose the word in a list that begins with capital letter in quotes, but is it possible to do it without having to do that.
I don't think there is a (better) way to do it instead of my_write(['How', are, you]).
BTW, you need to quote not only terms starting with a capital letter, but also terms starting with an underscore sign, or terms with spaces in their names.
SWI-Prolog has code_type/2 to handle character duties, with a not very user friendly syntax.
If you need to make upper case the first letter of an atom:
upcase_first_char(Plain, Proper) :-
atom_codes(Plain, [First|Cs]),
code_type(First, to_lower(Upcase)),
atom_codes(Proper, [Upcase|Cs]).
yields
?- upcase_first_char(carlo, V).
V = 'Carlo'.
to be used, in your case, like
my_write([First|Rest]) :-
upcase_first_char(First, Upper),
maplist(writeln, [Upper|Rest]).
yields
?- my_write([how, are, you]).
How
are
you

Prolog program- implementing rules and list matching

I am trying to write a program in Prolog that would recognize 'is a' statements and apply the transitive property in inquired. For example:
Input: Mary is a girl.
Output: ok.
Input: A girl is a human.
Output: ok.
Input: Is Mary a human?
Output: yes.
Here's my code:
begin :-
begin(Input).
begin(Input) :-
write('Begin.. '),
write('\n'),
readln(Input),
tokenize_atom(Atom, List),
rules(List).
begin.
rules(['A', Subj, is, a, What]) :-
asserta(a(Subj, What)),
write('ok'),
write('\n').
rules([Subj, is, a, What]) :-
asserta(is(Subj, What)),
write('ok'),
write('\n').
rules(['Is', Subj, a, What]) :-
(is(Subj, Z) ; a(Z, What)) -> (write('Yes.'), nl)
; (write('Unknown.'), nl).
It doesn't go into any of the cases, it will just say true and terminate when given a statement. What am I doing wrong?
Prolog itself wants to help you. Look at the helpful messages you get:
|: begin :-
|: begin(Input).
Warning: user://1:9:
Singleton variables: [Input]
This is pointing out that this rule is no different from:
begin :- begin(_).
This is highlighting that the role of Input in begin/1 is ambiguous. Is it input or output? If you can use it like this, it must be output, and that's consistent with how it's used in its definition, but look at the other problem you have there:
|: begin(Input) :-
|: write('Begin.. '),
|: write('\n'),
|: readln(Input),
|: tokenize_atom(Atom, List),
|: rules(List).
Warning: user://1:14:
Singleton variables: [Atom]
Where did Atom and List come from? Presumably you wanted one of those to show up from readln/1. What's actually going on here is that you're asking Prolog to input a value, which you then return, having done nothing with it; meanwhile Prolog materializes Atom and List from thin air and uses them with your rules/1 predicate. So clearly something isn't hooked up here that should be.
Then you have an obvious typo:
|: begin.
Warning: user://1:22:
Clauses of begin/0 are not together in the source-file
I suspect you meant a comma after rules(List) instead of a period.
Try fixing those problems and see if you make some progress.

Prolog, working with multiple predicates

I've just starting working with Prolog and I don't understand how to work with multiple predicates.
For example I have to solve the following problem: Substitute in a list a value with all the elements of another list.
This is the code that I managed to write so far:
domains
elem=integer
list=elem*
predicates
%append to a list already created another list. There are 3 list parameters
%because I don't know other method
append (list,list,list)
%This will search the list (the first one) for the searched element and
%it is it will replace it with the list(the second one). The result will be
%kept in the third list.
add(list,list,elem,list)
goal
add([1,2,3,2,1],[4,5],2,L),
write (L).
clauses
add ([],[_],_,[]).
add ([A|L],L1,E,[A|L2]):-
add(L,L1,E,L2).
add ([E|L],L1,E,L2):-
add(L,L1,E,L2).
append([],[],L2).
append([],[X|L1],[X|L2]):-
append([],L1,L2).
Does your append definition is working? I think should be
append([], L, L).
append([X|Xs], Ys, [X|Zs]):-
append(Xs, Ys, Zs).
The append predicate it's one of the most basic tools in Prolog programming, better to keep the usual behaviour, or to change name...
Instead of add, a better name could be replace_elem_with_list.
To implement it you should iterate, inspecting each element, and when you find a match to what's required to replace append the list instead of copying the element.
Something like
% replace_elem_with_list(ToSearch, Replacement, SoughtElem, Result)
replace_elem_with_list([E|Es], Replacement, E, Result) :-
!, replace_elem_with_list(Es, Replacement, E, Rs),
append(Replacement, Rs, Result).
I'll leave you the other 2 cases that you will need to cover (when element doesn't match and recursion base, which are similar to append)
the result:
?- replace_elem_with_list([1,2,3,4,2,3,4],[a,b],2,L).
L = [1, a, b, 3, 4, a, b, 3, 4].