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