Fail to set input and output in prolog - prolog

I am doing a prolog practice which is taken from this.
What I want to do now is to change the input and output way of the program.
I need to execute the program by typing this in the console:
goldbach(100, L).
just for example, and I need to press [;] to show next result when previous one is printed on the screen.
L = [3, 97];
L = [11, 89];
L = ....
However, what I want to make is like below:
Input a number:100.
L = [3, 97].
L = [11, 89].
.....
That is the program will print "Input a number:" first and read your input, then automatically print out all possible result.
I have read sections about read() and write, but I get fail when I add these:
read_gold :-
write('Input a number:'),
read(X),
write(goldbach(X, L)).
How can I fix my code to make the program to achieve the input and output that I want? Thanks for answering.

Something like this will do literally what you're asking for, although it's not normally how one uses Prolog queries and solutions.
read_gold :-
write('Input a number:'),
read(X),
show_results(goldbach(X)).
show_results(Query) :-
call(Query, L),
write('L = '), write(L), write('.'), nl,
fail.
show_results(_).
A cleaner way to collect all of the solutions in one go is to list them using findall/3:
read_gold(Solutions) :-
write('Input a number:'),
read(X),
findall(L, goldbach(X, L), Solutions).
Or, without explicitly prompting:
read_gold(X, Solutions) :-
findall(L, goldbach(X, L), Solutions).
And query it as, for example:
?- read_gold(100, Solutions).
Solutions = [[3, 97], [11,89], ...]

Related

Why doesn't prolog stop on cut?

I would like to get this result:
?- numberMatrixLines(1,[[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1]],X).
X = [machinePenalty(1,[1,1,1,1,1,1,1,1]),
machinePenalty(2 [1,1,1,1,1,1,1,1]),
machinePenalty(3,[1,1,1,1,1,1,1,1])]
I try the following code:
numberMatrixLines(X,[],ResultMatrix):-
writeln('should end here'),
reverse(ResultMatrix,ResultMatrixTemp),
initWith(ResultMatrixTemp,ResultMatrix),
!.
numberMatrixLines(X,[H|T],ResultMatrix):-
append_in_front(machinePenalty(X,H),ResultMatrix,ResultMatrixTemp),
writeln(ResultMatrixTemp),
incr(X,X1),
numberMatrixLines(X1,T,ResultMatrixTemp).
incr(X, X1) :-
X1 is X+1.
append_in_front(X,[],[X]).
append_in_front(X,L1,[X|L1]).
The result is correct when numberMatrixLines(X,[],ResultMatrix) is reached. HOWEVER, the predicate won't stop there and return X , as it's supposed to.
What can be done to make it stop in that line?
A straight-forward solution would be (I moved the input list to the first argument to take advantage of Prolog first-argument indexing to avoid spurious choice-points and the need of cuts):
% number_matrix_lines(+list, +integer, -list)
number_matrix_lines([], _, []).
number_matrix_lines([Line| Lines], I, [machine_penalty(I,Line)| NumberLines]) :-
J is I + 1,
number_matrix_lines(Lines, J, NumberLines).
Sample call:
| ?- number_matrix_lines([[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1]], 1, NumberLines).
NumberLines = [machine_penalty(1,[1,1,1,1,1,1,1,1]), machine_penalty(2,[1,1,1,1,1,1,1,1]), machine_penalty(3,[1,1,1,1,1,1,1,1])]
yes
P.S. Note that Prolog coding guidelines advise using underscores in predicate names instead of CamelCase.

How to parsing list in prolog until not fail

I am trying to parse a list, for example:
[1,3,3,2,2,7,2,9]
Let's say I have the following code, where isTwo will print No and fail if it is anything other than two. I WANT it to fail if it is anything other than two. If it is a two, it will print Yes and succeed.
isTwo(2) :-
write('Yes'), !.
isTwo(_) :-
write('No'), fail.
My issue is that I have something along the lines of an iterator defined, and I want to parse an entire list to find the first success.
iter([]).
iter([Head|Tail]) :-
isTwo(Head),
iter(Tail).
This works fine but will stop parsing the rest of the list as soon as failure is found. If we go back to the original list, [1,3,3,2,2,7,2,9], we get false as our output.
My question here is: how can I continue to parse in prolog while still ensuring that isTwo(_) (where it is not equal to two) will still fail, so that I can get an output of something such as NoNoNoYesYesNoYesNo in this case. Preferably without using an if-then-else clause.
This may help:
expected output: NoNoNoYesYesNoYesNo
observed output: No
Well an easy solution would be to use a second variable in iter that will help you understand if an number different than 2 is found:
isTwo(2, X, X) :-
write('Yes').
isTwo(_, _, 0) :-
write('No').
iter([], 0):- fail,!.
iter([], 1).
iter([Head|Tail], X) :-
isTwo(Head, X, Y),
iter(Tail, Y).
iter(L) :- iter(L, 1).
If you want a more concise solution, using maplist/2 you can do something like:
isTwo(2) :- write('Yes'), !.
isTwo(_):- write('No').
test(L):-
maplist(isTwo,L).
?- test([1,3,3,2,2,7,2,9]).
NoNoNoYesYesNoYesNo
true
test/1 is not mandatory, i've added it only for sake of clarity...
The other answers are both fine but the haphazard mixing in of side effects makes me a bit nervous. Also, you have a problem if the list you are "parsing" has a free variable (it will become 2 silently).
Why not like this:
is_two(X) :- X == 2, !, format("Yes").
is_two(X) :- X \== 2, !, format("No").
and then:
?- forall(member(X, [1,3,3,2,2,7,2,9]), is_two(X)).
NoNoNoYesYesNoYesNo
true.
?- forall(member(X, [Y, 2, Z]), is_two(X)).
NoYesNo
true.
Use == and \== to compare without unifying. Use forall and member to make it clear that you are doing it for the side effect. Traversing a list (or using maplist) is a bit deceiving.
forall is just a clearer way to do a failure-driven loop using negation instead of cuts and fails. The query above is identical to:
?- \+ ( member(X, [1,3,3,2,2,7,2,9]), \+ is_two(X) ).

How can I get the type of a term in SWI Prolog

Is there a way to know what type is a variable in Prolog?
I have the code
test:-
writeln('Please enter the absolut file name :'),
read(FileName),
write('Opening file '),
write(FileName),nl,
open(FileName,read,Stream),
read_file(Stream,Lines),
close(Stream),
parseLines(Lines).
% used on reading the text file
read_file(Stream,[]) :-
at_end_of_stream(Stream).
% used on reading the text file
read_file(Stream,[X|L]) :-
\+ at_end_of_stream(Stream),
read(Stream,X),
read_file(Stream,L).
parseLines(Lines):-
%primele 2 linii contin lista cu barbatii si list cu femeile iar
%restul liniilor contin preferintele acestora
Lines=[LB|[LF|LPrefs]],
writeln(LB),
atom_length(LB,2).
And I get the error (when running test)
ERROR: [Thread pdt_console_client_0_Default Process] atom_length/2: Type error: `list' expected, found `man([m1,m2])'
The input text file contains
man = {m1, m2}.
women = {w1, w2}.
m1: w1 > w2.
m2: w1 > w2.
w1: m1 > m2.
w2: m1 > m2.
I am trying to parse that file but anything I try I get that error, like the things in the Lines read from the file are not string,atoms , I have no idea what to do to fix this.
P.S.Any idea on how to fast/simple parse the file? It feels strange that parsing the input for the problem is much harder then solving the problem.
Thanks.
Edit: I found the compound predicate and the line read from files is a compound term.
Edit2:
My goal is to read the data in that file and assert it or similar, I want to solve the stable marriage problem, I solve it but I can't figure out this part of reading the input from this file format.
Edit3:
I have other input files that have lines like:
alan: christine > tina > zoe > ruth > sarah.
and this lines fail when trying to read them as terms with read_file_to_terms because of the multiple > operators, so I think not all my inputs are valid Prolog
Since you tagged your question [swi-prolog], and your file contains valid Prolog terms, you could use read_file_to_terms/3, and load the list in a single call (this hint is for P.S. part). After that you must process your terms' list: your parseLines/1 it's useless. Just as example of list processing, I'll display each loaded term:
?- read_file_to_terms('/home/carlo/x.txt',L,[]), maplist(writeln, L).
man={m1,m2}
women={w1,w2}
m1:w1>w2
m2:w1>w2
w1:m1>m2
w2:m1>m2
L = [man={m1, m2}, women={w1, w2}, m1:w1>w2, m2:w1>w2, w1:m1>m2, w2:m1>m2].
edit I think {} is named 'set constructor', it's just a weird shape for a compound:
?- write_canonical({a,b,c}).
{}(','(a,','(b,c)))
you can use univ to get the list of arguments
?- {a,b,c} =.. X.
X = [{}, (a, b, c)].
bug in previous edit
=.. seems of little relevance, because more than a compound, {} resembles an operator, both prefix and postfix (i.e. combining in some way op(xf,,({)) and op(fx,,(}))).
AFAIK converting 'the set' to a list requires something like
setcons_to_list(S, L) :-
S =.. [{}, E] -> andexpr_to_list(E, L) ; L = [].
andexpr_to_list((E,Es), [E|Ts]) :-
!, andexpr_to_list(Es, Ts).
andexpr_to_list(E, [E]).
test
?- setcons_to_list({},L).
L = [].
?- setcons_to_list({1,2,3,4},L).
L = [1, 2, 3, 4].
more edit
Prolog operators are 'configurable', it's possible to instruct the parser about that preference list. Add an op declaration in your source :- op(10,xfy,(>)).. Here a sample using the prompt
?- op(10,xfy,(>)).
true.
?- X = (alan: christine > tina > zoe > ruth > sarah),write_canonical(X).
:(alan,>(christine,>(tina,>(zoe,>(ruth,sarah)))))
X = alan:christine>tina>zoe>ruth>sarah.
beware: changing the predefined associativity should be done with care. Otherwise, this other answer could be useful if you prefer to craft a more general parser, using DCGs.

How to write a predicate listtran(L, R)?

How to write a predicate listtran(L, R),
L is [0,1,2,3,4,5,6,7,8,9,10],
R is [zero, one, ..., ten]
Example:
?- listtran([0,4,5], L).
L = [zero, four, five].
?- listtran(L, [two, ten, two]).
L = [2, 10, 2].
if you only have to go from 0-10, I would definitely start building a predicate that translates numbers to text names:
num(0,zero).
num(1,one).
num(2,two).
num(3,three).
num(4,four).
num(5,five).
num(6,six).
num(7,seven).
num(8,eight).
num(9,nine).
num(10,ten).
then using them in the listtran predicate is easy:
listtran(IntLst,TxtLst) :-
maplist(num,IntLst,TxtLst).
to build this in a clearer way without the helper maplist predicate, try this:
listtran([],[]). %base rule
listtran([Int|IntRest], [Txt|TxtRest]) :-
num(Int,Txt),
listtran(IntRest,TxtRest).
Form a pairing domain, PairDom = [0-zero, 1-one, 2-two, ...] and use member( X1-Y1, PairDom):
pair(A,B,A-B).
listtran(L,R):-
maplist(pair,[0,1,2,3, ...,10],[zero,one, ...,ten],PairDom),
maplist(pair,L,R, ...),
maplist(member, ...).
To get a feel for how this might work, try it:
?- PairDom=[0-zero, 1-one, 2-two], member(1-Y1,PairDom).
Y1 = one
?- PairDom=[0-zero, 1-one, 2-two], member(X1-three,PairDom).
No.

read numbers from file in prolog and sorting

how to read numbers from file and sorting that in (prolog programming)
You can first try the following, reading multiple lines from the console:
?- repeat, read(X), (X==end_of_file, !, fail; true).
1.
X = 1 ;
2.
X = 2 ;
No
Explanation: The repeat/0 predicate repeatedly succeeds so that
read/1 is called over and over. Calling read/1 only stops when end_of_file
has been reached because of the cut that follows it.
Then you can wrap it into a findall/3 and call sort/2:
?- findall(X,(repeat, read(X), (X==end_of_file, !, fail; true)),L), sort(L,R).
2.
1.
L = [2, 1],
R = [1, 2]
If needed you can use your own sort and enhance the read by a stream argument.
Best Regards

Resources