I have this code where I want to print a board in the console. The code is working as expected in terms of printing it but in the end of doing so it returns "no", instead of yes. How can I make this recursion return true?
Main code:
printLine(_,Size,Size).
printLine([H1,H2|R],Size,Indice) :-
write(H1), write(' '), write(H2), write(' '),
IndiceNovo is Indice+1,
printLine(R,Size,IndiceNovo).
printTops([]).
printTops([H|T]) :- write(H),write(' '),printTops(T).
printBoard(_,_,Size,Size*2,_):- nl,nl, write('end').
printBoard(Numeros,Topos,Size,Indice,BarrelIndex):-
calculateDiv(Size,D), nl,
writeDiv(D), nl,
TopoIndex1 is (1+BarrelIndex*Size),
TopoIndex2 is (Size + BarrelIndex*Size),
slice(Topos,TopoIndex1,TopoIndex2,TopsTemp),
write(' '), printTops(TopsTemp),nl,
Indice2 is Indice+1,
Index1 is (1+Indice*Size*2), Index2 is (Size*2 + (Indice*Size*2)),
slice(Numeros,Index1,Index2,Linha),
printLine(Linha,Size,0),nl,
Index21 is (1+(Indice2*Size*2)), Index22 is (Size*2 + (Indice2*Size*2)),
slice(Numeros,Index21,Index22,Linha2),
printLine(Linha2,Size,0),nl,
IndiceNovo is Indice+2, NovoBarrelIndex is BarrelIndex+1,
printBoard(Numeros,Topos,Size,IndiceNovo,NovoBarrelIndex).
printBoard(Board,Topos):-
length(Topos,Size),
Size1 is truncate(sqrt(Size)),
printBoard(Board,Topos,Size1,0,0).
Test Code:
p:-
B= [1,2,3,4,5,6,7,8,3,4,1,5,7,8,2,6,2,1,4,3,6,7,8,5,5,7,6,8,1,3,4,2,4,6,8,7,3,2,5,1,7,8,2,1,4,5,6,3,6,3,5,2,8,4,1,7,8,5,7,6,2,1,3,4],
T= [10,13,26,23,15,21,17,19,25,18,14,90,22,20,64,84],
printBoard(B,T).
My output:
you need to evaluate arithmetic with is/2.
printBoard(_,_,Size,Size2,_):- Size2 is Size*2, nl,nl, write('end').
Related
This is the current code I have for a problem I am working on. It is supposed to read in from a file, and increment a counter, R, every time it comes across a vowel.
Currently, I have it stop when reaching a vowel, but I would like it to increment a counter, then continue processing. Once done, I want it to print R to the console. Thanks in advance!
readWord(InStream, W) :-
get0(InStream,Char),
checkChar_readRest(Char,Chars,InStream, R),
atom_codes(Code,Chars),
write(Code).
%checkChar_readRest(10,[],_) :- !. % Return
%checkChar_readRest(32,[],_) :- !. % Space
checkChar_readRest(-1,[],_,_) :- !. % End of Stream
checkChar_readRest(97,[],_,R) :- !. % a
checkChar_readRest(101,[],_,R) :- !. % e
checkChar_readRest(105,[],_,R) :- !. % i
checkChar_readRest(111,[],_,R) :- incr(R,R1), write(R1). % o
checkChar_readRest(117,[],_,R) :- !. % u
%checkChar_readRest(end_of_file,[],_,_) :- !.
checkChar_readRest(Char,[Char|Chars],InStream,R) :-
get0(InStream,NextChar),
checkChar_readRest(NextChar,Chars,InStream,R).
incr(X, X1) :- X1 is X+1.
vowel(InStream, R) :-
open(InStream, read, In),
repeat,
readWord(In, W),
close(In).
Here's my attempt (ISO predicates):
% open Src, count vowels, close stream, print to console
count_vowels_in(Src) :-
open(Src, read, Stream),
count(Stream, Total),
close(Stream),
% cutting here because our Stream is now closed, any backtracking will break things that rely on it
% you could also put this after at_end_of_stream/1 in count_/3
% not sure what best practices are here
!,
write(Total).
% just a nice wrapper to get started counting with the initial count set to 0
count(Stream, Total) :-
count_(Stream, 0, Total).
% at end of stream, Count = Total and we're done
count_(Stream, Count, Count) :-
at_end_of_stream(Stream).
% read from stream recursively, incrementing Count as needed
count_(Stream, Count0, Total) :-
\+at_end_of_stream(Stream),
get_char(Stream, Char),
char_value(Char, Value),
Count1 is Count0 + Value,
% recursively call count_, but now with our new Count1 value instead, carrying forward the results
count_(Stream, Count1, Total).
char_value(Char, 1) :-
vowel(Char).
char_value(Char, 0) :-
\+vowel(Char).
vowel(a).
vowel(e).
vowel(i).
vowel(o).
vowel(u).
The biggest difference is that I use two variables for keeping track of the count. Count (equivalent to your R) is the current count, and Total is a variable representing the final count. We unify Total with Count when we are finished counting: at the end of the stream.
In the original program posted, there were many singleton variables (variables that are never unified with anything, for example W). This is usually indicative of a bug and will generate warnings. Remember that Prolog is a logical language, it can be good to take a step back and think "what am I actually trying to do with these variables?". It can also help to break the problem down into smaller chunks instead of trying to write one predicate that does everything.
I might approach it like this:
Slurp in the entire file as a list of characters.
Traverse that list and tally the vowels it contains.
Write the tally.
Something like
findall(C, ( get0(V) , V \= -1 , char_code(C,V) ), Cs).
should suffice for slurping the text.
And then, something along these lines:
count_vowels :-
findall(C, ( get0(V) , V \= -1 , char_code(C,V) ), Cs),
count_vowels(Cs,N),
writeln( total_vowels : N )
.
count_vowels( S , N ) :- string(S), !, string_chars(S,Cs), count_vowels(Cs,N) .
count_vowels( Cs , N ) :- count_vowels(Cs,0,N) .
count_vowels( [] , N , N ) .
count_vowels( [C|Cs] , T , N ) :- tally(C,T,T1), count_vowels(Cs,T1,N).
tally( C , M , N ) :- vowel(C), !, N is M+1 .
tally( _ , N , N ) .
vowel( a ).
vowel( e ).
vowel( i ).
vowel( o ).
vowel( u ).
So let's say I'm trying to find the sum of all factors of 5 below a certain maximum number. I'm doing this recursively, because that seemed easiest. This is my code:
isFactor(X):-
Y is X mod 5,
Y = 0.
sumAll(Number, Result):-
sumAll(Number, 0, Result).
sumAll(Number, RunningTotal, Result):-
(isFactor(Number) ->
NextTotal is RunningTotal + Number;
NextTotal is RunningTotal),
NextNumber is Number - 1,
(NextNumber > 0 ->
mulSum(NextNumber, NextTotal, NextResult);
NextResult is RunningTotal),
number(NextResult) -> % this test is so that the interpreter
write(NextResult), nl; % doesn't print out a bunch of extra stuff
true. % (the internal IDs of each binding of
% NextResult maybe?) after the answer.
Now, this works (that is, it prints the correct sum), but I am slightly miffed that I can't figure out how to arrange the code so that doing
| ?- sumAll(10, X).
binds X to 10, rather than printing '10' and asserting 'yes' at the end.
My instinct is to somehow rebind Result to NextResult if NextNumber > 0 (line 13) is true, but I suspect that's just years of Python programming trying to assert themselves.
Is there a way of 'returning' the result of a goal all the way up the nested recursions here? Or am I just thinking about this all wrong?
That's awfully complicated for something simple. To sum all elements of a list that are divisible by N, all you need is this tail recursive implementation:
sum_all( Xs , N , Sum ) :-
sum_all( Xs , N , 0 , Sum )
.
sum_all( [] , _ , S , S ) .
sum_all( [X|Xs] , N , T , S ) :-
X mod N =:= 0 ,
! ,
T1 is T+X ,
sum_all(Xs,N,T1,S)
.
sum_all( [_|Xs] , N , T , S ) :-
sum_all(Xs,N,T,S)
.
The non-tail recursive implementation is a bit simpler but will blow its stack on a long list:
sum_all( [] , _ , 0 ) .
sum_all( [X|Xs] , N , S ) :-
sum(Xs,N,T) ,
( X mod N =:= 0 -> S is T+X ; S is T )
.
You could even do something like this to decompose the extraction of "interesting" values from the summing of the list:
sum_all(Xs,N,Sum) :-
findall( X , ( member(X,Xs), X mod N =:= 0 ) , L ) ,
sum(L,Sum)
.
sum(L,S) :- sum(L,0,S).
sum( [] , S ,S ) .
sum( [X|Xs] , T ,S ) :- T1 is T+X , sum(Xs,T1,S) .
Once you have that, then you can simply say:
sum_modulo_N_values( Xs , N ) :-
sum_all(Xs,N,Sum) ,
writenl( sum = Sum )
.
Invoke it something like this
sum_modulo_N_values( [1,2,5,6,7,10,11,15,31,30] , 5 ) .
And you'll get the the expected sum = 60 written to the console.
Your code seems more complex than needed, maybe such complexity hides an important fact:
in sumAll(Number, RunningTotal, Result):- Result is a singleton. Then there are little chances to get back the computed value.
I would try to get rid of number(NextResult) -> etc.. (btw you usually need parenthesis to get the expected nesting when using if/then/else - that is (C -> T ; F) ), and 'assign' instead to Result.
Given the code below, I am trying to call the last rule: trans([[p],[q],[r]]).
This should then recursively call trans([P]), write, trans([P],[Q]]).
However it appears to be calling trans([P]), write, trans([P,Q]).
Is there a way to override the reserved square bracket? Is there a better way to enable the recursion?
trans([P]) :- atom(P), write(P).
trans([~P]) :- write('Not '), trans([P]).
trans([P,Q]) :- trans(P), write(' or '), trans(Q).
trans([P,Q,R]) :- trans([P]), write(' or '), trans([Q,R]).
trans([P,Q,R,S]) :- trans([P]), write(' or '), trans([Q,R,S]).
trans([[P],[Q]]) :- trans([P]), write(' and '), trans([Q]).
trans([[P,Q],[R]]) :- trans([P,Q]), write(' and '), trans([R]).
trans([[P],[Q,R]]) :- trans([P]), write(' and '), trans([Q,R]).
trans([[P,Q],[R,S]]) :- trans([P,Q]), write(' and '), trans([R,S]).
trans([[P],[Q],[R]]) :- trans([P]), write(' and '), trans([[Q],[R]]).
Terminal Output:
?- trans([[p],[q],[r]]).
p and q or r
true ;
q and r
true .
Perhaps something like this. There's a bit of splitting out of clauses to make the parenthesis come out nice.
% Handle the top, conjunction level
trans([H]) :- % A single atomic conjunctive term
atom(H), write(H).
trans([H]) :- % A single non-atomic conjunctive term
trans_dis(H).
trans([H1,H2|T]) :- % Multiple conjunctive terms
trans_conj([H1,H2|T]).
trans_conj([H1,H2|T]) :- % Multiple conjunctive terms
trans_conj([H1]), write(' and '), trans_conj([H2|T]).
trans_conj([H]) :- % Single atomic conjunctive term
atom(H), write(H).
trans_conj([[H]]) :- % Last conjunctive term, single disjunction
trans_dis([H]).
trans_conj([[H1,H2|T]]) :- % Last conjunctive term, multiple disjunctions
write('('), trans_dis([H1,H2|T]), write(')').
% Handle the disjunctions level
trans_dis([H]) :- % Single disjunctive term
atom(H), write(H).
trans_dis([~H]) :- % Single negated disjunctive term
atom(H), write('not '), write(H).
trans_dis([H1,H2|T]) :- % Multiple disjunctive terms
trans_dis([H1]), write(' or '), trans_dis([H2|T]).
Some test results:
| ?- trans([p]).
p
true ? a
no
| ?- trans([[p]]).
p
true ? a
no
| ?- trans([p,q]).
p and q
true ? a
no
| ?- trans([[p,q]]).
p or q
true ? a
no
| ?- trans([[p],[q]]).
p and q
true ? a
no
| ?- trans([[p,r],[q]]).
(p or r) and q
true ? a
no
| ?- trans([[p,r],[q,s]]).
(p or r) and (q or s)
| ?- trans([[a,~b,c],[d,e],[f]]).
(a or not b or c) and (d or e) and f
true ? a
(1 ms) no
You query:
?- trans([[p],[q],[r]]).
gets instantiated with
trans([P,Q,R]) :- trans([P]), write(' or '), trans([Q,R]).
(or: the 4th clause of trans/1). You want it to instantiate with
trans([[P],[Q],[R]]) :- trans([P]), write(' and '), trans([[Q],[R]]).
(or: the 10th clause of trans/1).
The reason why this happens is that trans([[p],[q],[r]]) unifies with [P,Q,R] according to the following substitution: P = [p], Q = [q], and R = [r].
Proper use of recursion
Your code looks a little verbose for Prolog code. I therefore give a possible rewrite here that uses recursion proper.
Instead of:
trans([P,Q]) :- trans(P), write(' or '), trans(Q).
trans([P,Q,R]) :- trans([P]), write(' or '), trans([Q,R]).
trans([P,Q,R,S]) :- trans([P]), write(' or '), trans([Q,R,S]).
you can also write:
trans([]).
trans([H|T]):-
trans(H),
trans(T).
... and that works for any list argument that is given to trans/1.
Distinguish disjunction from conjunction
You are not making the distinction between conjunction and disjunction correctly yet, you may want to try out:
trans(and([]).
trans(and([H])):-
trans(H).
trans(and([H|T])):-
trans(H),
write(' and '),
trans(and(T)).
trans(or([])).
trans(or([H])):-
trans(H).
trans(or([H|T])):-
trans(P),
write(' or '),
trans(or(T)).
Prolog, recursive function:
i want it to print the C with each element of the list
for example: C=30 and [H|T]= [-9,-10,-30]
myfunc(C,[H|T]):-
(\+([H|T]=[])),
write(C), write(' with '), write(H), nl,
myfunc(C,T).
i check at the beginning that the head of the list is not empty. it gives me this output
30 with -9
30 with -10
30 with -30
(32 ms) no
this output is what i want but i dont want to get a 'no' at the end because this makes the parent function to fail as well!
how can i remove it and put a 'yes' instead?
Simple way: just add a base case with the empty list.
myfunc(_, []) :- !.
myfunc(C,[H|T]):-
write(C), write(' with '), write(H), nl,
myfunc(C,T).
test:
?- myfunc(30, [1, 2, 3]).
30 with 1
30 with 2
30 with 3
true.
I don't know if this is the best way to do that, but you didn't give us much details about your whole program, so I opted for a small modification of your predicate.
If you have maplist in your Prolog, you can write
myfunc(N, L) :-
maplist(my_write(N), L).
my_write(N, Val) :-
format('~w with ~w~n', [N, Val]).
With SWI-Prolog and module lambda
:- use_module(library(lambda)).
myfunc(N, L) :-
maplist(\X^format('~w with ~w~n', [N, X]), L).
I need write a prolog program that read from keyboard such positive numbers until the user writes 'stop' and builds a binary dictionary without duplicates.
I try:
:-dynamic tree/1.
run:-
retractall(tree(_)),
write('Input N '), read(N),
insert(N,empty,T),
assert(tree(T)),
start(N),nl,
tree(T),write(T),!.
start(stop):-!.
start(N):-
N \= stop,
tree(T),
insert(N,T,NewTree),
assert(tree(NewTree)),
write('Input N '), read(M),
start(M).
insert(NewItem,empty,tree(NewItem,empty,empty)):- !.
insert(NewItem,tree(Element,Left,Right),tree(Element,NewLeft,Right)):-
NewItem #< Element,
!,insert(NewItem,Left,NewLeft).
insert(NewItem,tree(Element,Left,Right),tree(Element,Left,NewRight)):-
insert(NewItem,Right,NewRight).
Can anyone help me?
Two mistakes here. First of all, the first element is being inserted twice due to the explicit call to insert in the body of run, and to the call to start that will also call insert. Instead of doing this, you need to start by recording the empty tree. Second, it is not enough to consult which tree is currently being recorded, you need to remove the previous version of the tree and record the current one.
Fixing these two mistakes leads to the following solution:
:-dynamic tree/1.
run:-
retractall(tree(_)),
write('Input N '), read(N),
assert(tree(empty)), % 1. initially the tree is empty
start(N),nl,
tree(T),write(T),!.
start(stop):-!.
start(N):-
N \= stop,
retract(tree(T)), % 2. changed here
insert(N,T,NewTree),
assert(tree(NewTree)),
write('Input N '), read(M),
start(M).
insert(NewItem,empty,tree(NewItem,empty,empty)):- !.
insert(NewItem,tree(Element,Left,Right),tree(Element,NewLeft,Right)):-
NewItem #< Element,
!,insert(NewItem,Left,NewLeft).
insert(NewItem,tree(Element,Left,Right),tree(Element,Left,NewRight)):-
insert(NewItem,Right,NewRight).
On a slightly different note, you might ask yourself whether you really need to do all this asserting/retracting as you can pass the currently constructed tree as an argument of the start predicate.
Eliminating asserts and retracts gives the following version:
run:-
write('Input N '), read(N),
start(N, empty, T),nl,
write(T).
start(stop, T, T):-!.
start(N, CurTree, FinalTree):-
N \= stop,
insert(N,CurTree,NewTree),
write('Input N '), read(M),
start(M, NewTree, FinalTree).
insert(NewItem,empty,tree(NewItem,empty,empty)):- !.
insert(NewItem,tree(Element,Left,Right),tree(Element,NewLeft,Right)):-
NewItem #< Element,
!,insert(NewItem,Left,NewLeft).
insert(NewItem,tree(Element,Left,Right),tree(Element,Left,NewRight)):-
insert(NewItem,Right,NewRight).
Finally, observe that the cut in the first clause of start and the intended use of stop with the first and the second arguments being bound while the third one being free, makes the explicit check N\= stop redundant. This gives us the final version of the solution:
run:-
write('Input N '), read(N),
start(N, empty, T),nl,
write(T).
start(stop, T, T):-!.
start(N, CurTree, FinalTree):-
insert(N,CurTree,NewTree),
write('Input N '), read(M),
start(M, NewTree, FinalTree).
insert(NewItem,empty,tree(NewItem,empty,empty)):- !.
insert(NewItem,tree(Element,Left,Right),tree(Element,NewLeft,Right)):-
NewItem #< Element,
!,insert(NewItem,Left,NewLeft).
insert(NewItem,tree(Element,Left,Right),tree(Element,Left,NewRight)):-
insert(NewItem,Right,NewRight).