Related
I have list of facts as follows.
items(itemId('P01'),prodName('Pots'),stockQty(50),price(8200)).
items(itemId('P02'),prodName('Pans'),stockQty(50),price(400)).
items(itemId('P03'),prodName('Spoons'),stockQty(50),price(200)).
items(itemId('P04'),prodName('Forks'),stockQty(50),price(120)).
items(itemId('P05'),prodName('Kettles'),stockQty(50),price(500)).
items(itemId('P06'),prodName('Plates'),stockQty(50),price(60)).
How to print on the console something like the following when a command like print_all_products. is given.
..............
Available Products
..........
Name Qty
Pots 60
Pans 50
Spoons 40
..................
The Name and Qty must be properly formatted in a tabular structure.
I tried using forall and foreach I am unsuccessful in generating what i need.
Answer with more details is posted here.
Below is the code so that this is not a link only answer.
items(itemId('P01'),prodName('Pots'),stockOty(50),price(8200)).
items(itemId('P02'),prodName('Pans'),stockOty(50),price(400)).
items(itemId('P03'),prodName('Spoons'),stockOty(50),price(200)).
items(itemId('P04'),prodName('Forks'),stockOty(50),price(120)).
items(itemId('P05'),prodName('Kettles'),stockOty(50),price(500)).
items(itemId('P06'),prodName('Plates'),stockOty(50),price(60)).
header("\n........................\nAvailable Products\n........................\nName Qty\n").
footer("........................\n").
spaces(Length,Spaces) :-
length(List,Length),
maplist([_,0'\s]>>true,List,Codes),
string_codes(Spaces,Codes).
padded_string(String,Width,Padded_string) :-
string_length(String,String_length),
Padding_length is Width - String_length,
spaces(Padding_length,Padding),
atom_concat(String,Padding,Padded_string).
format_detail_line(item(Name,Quantity),width(Name_width),Formatted_item) :-
padded_string(Name,Name_width,Padded_name),
atom_concat(Padded_name,Quantity,Formatted_item).
add_detail_line(width(Name_Width),Item,Lines0,Lines) :-
format_detail_line(Item,width(Name_Width),Formatted_item),
atomic_list_concat([Lines0,Formatted_item,"\n"], Lines).
items_detail(Detail) :-
findall(item(Name,Quantity),items(_,prodName(Name),stockOty(Quantity),_),Items),
aggregate_all(max(Width),Width,(items(_,prodName(Name),_,_),string_length(Name,Width)),Name_Width),
Name_field_width is Name_Width + 1,
foldl(add_detail_line(width(Name_field_width)),Items,"",Detail).
print_all_products(Report) :-
header(Header),
items_detail(Detail),
footer(Footer),
atomic_list_concat([Header,Detail,Footer], Report).
print_all_products :-
print_all_products(Report),
write(Report).
:- begin_tests(formatted_report).
test(1) :-
print_all_products(Report),
with_output_to(atom(Atom),write(Report)),
assertion( Atom == '\n........................\nAvailable Products\n........................\nName Qty\nPots 50\nPans 50\nSpoons 50\nForks 50\nKettles 50\nPlates 50\n........................\n' ).
:- end_tests(formatted_report).
Note: The answer given by Peter is the customary way to do the formatting, but as I noted, that drives me nuts. Even so, that is the way I would do it in a production environment.
I gave this answer because the OP noted they were looking for a way to do it using predicates like forall/2 or foreach/2. Granted neither of them is used in this answer but the intent of using a more functional approach is used.
If the question was more open ended I would have given a answer using DCGs.
format/2 ... for putting things in neat columns, use ~|, ~t, ~+.
~| sets a tab to "here", ~t inserts fill characters, ~+ advances the tab beyond the last "here" (~|) and distributes the fill characters. So,
format("(~|~`.t~d~5+)~n", [123])
produces (..123) -- the format string right-justifies the number with .s in a width of 5, surrounded by parentheses.
You are asking for SQL-style tabular output and yes, that should be in the language as basic predicate set since when Reagan was prez. I don't know what's going on. It's probably out there in a library though (but where is the library?)
Meanwhile, here is the "failure driven-loop" using some of my personal toolbox goodies, but it uses SWI Prolog:
In file printthem.pl:
:- use_module(library('heavycarbon/strings/string_of_spaces.pl')).
:- use_module(library('heavycarbon/strings/string_overwriting.pl')).
items(itemId('P01'),prodName('Pots'),stockOty(50),price(8200)).
items(itemId('P02'),prodName('Pans'),stockOty(50),price(400)).
items(itemId('P03'),prodName('Spoons'),stockOty(50),price(200)).
items(itemId('P04'),prodName('Forks'),stockOty(50),price(120)).
items(itemId('P05'),prodName('Kettles'),stockOty(50),price(500)).
items(itemId('P06'),prodName('Plates'),stockOty(50),price(60)).
printthem :-
% ideally these should be built by getting max(length) over a column - hardcode for now!
string_of_spaces(5,SpacesId),
string_of_spaces(10,SpacesName),
string_of_spaces(4,SpacesQuant),
string_of_spaces(6,SpacesPrice),
% begin failure-driven loop!
items(itemId(Id),prodName(Name),stockOty(Quant),price(Price)), % backtrack over this until no more solutions
% transform data into string; see predicate format/2;
% capture output instead of letting it escape to STDOUT
with_output_to(string(TxtId),format("~q",[Id])),
with_output_to(string(TxtName),format("~q",[Name])),
with_output_to(string(TxtQuant),format("~d",[Quant])),
with_output_to(string(TxtPrice),format("~d",[Price])),
% formatting consist in overwriting the space string with the data-carrying string
string_overwriting(SpacesId,TxtId, 1,TxtIdFinal),
string_overwriting(SpacesName,TxtName, 1,TxtNameFinal),
string_overwriting(SpacesQuant,TxtQuant, 1,TxtQuantFinal),
string_overwriting(SpacesPrice,TxtPrice, 1,TxtPriceFinal),
% output the line
format("~s~s~s~s\n",[TxtIdFinal,TxtNameFinal,TxtQuantFinal,TxtPriceFinal]),
% close the loop
fail.
The above is just an ébauche. Improvements are possible in several distinct directions.
The modules loaded via
:- use_module(library('heavycarbon/strings/string_of_spaces.pl')).
:- use_module(library('heavycarbon/strings/string_overwriting.pl')).
can be obtained from GitHub here. You will have to grab several files and arrange them appropriately. Read the script load_and_test_script.pl. Don't mind the mess, this is work in progress.
If everything has been set up correctly:
?- [printthem].
true.
?- printthem.
'P01' 'Pots' 50 8200
'P02' 'Pans' 50 400
'P03' 'Spoons' 50 200
'P04' 'Forks' 50 120
'P05' 'Kettles' 50 500
'P06' 'Plates' 50 60
false.
I got the following event: item(C,X,G,P), (where C is a number for the product,X it's name,G it's price,P it's cost).
When i use the command item(n3001,_,_,P) directly on the prolog console i get as answer
G = 1.25 X = 100 but when i write the equation p3(C)-: item(C,_,_,P). then i consult the text i get as answer yes.
My question clarified is how come the one time i get the value of P which i want and the other time i get whether it's true or false?
There are no return values in Prolog and p3/1 does not constitute a function but a relation. Your definition
p3(C) :-
item(C,_,_,P).
reads: If item(C,_,_,P) succeeds then p3(C) succeeds as well. For the sake of argument, let's assume that your code includes the following fact:
item(n3001,100,1.25,1).
If you query
?- p3(n3001).
Prolog unifies C in the head of your rule with n3001 and then tries your goal item(C,_,_,P) which succeeds. Hence the rule succeeds and Prolog tells you:
?- p3(n3001).
yes
If you want to know the price corresponding to n3001 you have to to define a rule where P appears in the head of the rule as well, e.g.:
p3(C,P) :-
item(C,_,_,P).
If you query that you'll get to see the value of P corresponding to n3001:
?- p3(n3001,P).
P = 1
If you query item/4 directly P appears in the arguments and therefore you get to see a substitution for it that satisfies your query:
?- item(n3001,_,_,P).
P = 1
I am trying to learn Prolog. I have a problem and the solution for that in Prolog. Though I am unable to understand the code completely.
The call of the code goes like this-
conc(Before,[c|After],[a,b,c,d]) .
This code will return
Before = [a,b]
After = [d]
I have the solution -
conc([],L,L).
conc([X|L1],L2,[X|L3]) :- conc(L1,L2,L3) .
I am not able to understand the flow of the program completely. Let me start with a dry run. I added some write command in order understand the code flow. The code now looks like this -
conc([],L,L):- write("Line1: "), write(L).
conc([X|L1],L2,[X|L3]) :-
write("Line-2: "), write(L1), write(" "),
write(L2), write(" "), write(L3), conc(L1,L2,L3) .
Initial call is -
conc(Before,[c|After],[a,b,c,d]) .
At this moment, the call goes to line 2 (because, Before is unknown term which is not empty)which is :
conc([X|L1],L2,[X|L3]) :-
write("Line-2: "), write(L1), write(" "),
write(L2), write(" "), write(L3), conc(L1,L2,L3) .
At this point, X=[a], l1= unknown, L2=[c|After] and L3=[b,c,d]. This prints -
Line2: _G481 [c|_G368] [b,c,d]
This will again call the recursion(code line 2) with the following value:
cons(L1, [c|After], [b,c,d]). (L1 is unknown still now)
And, prints -
Line2: _G494 [c|_G368] [c,d]
Now the next call will be :
cons(L1, [c|After], [c,d]).
But , I can see while printing the customized comments in the code, that, at this point the code control goes to #line 1 which I am not able to understand. Because, now,
L1= unknown(just as all the previous calls).
L(parameter 2)= [c|After]
L(parameter 3) = [c,d].
But, the control goes to the #line 1, and it prints :
Line1: [c,d]
I thought prolog executes the code from left to right. So, as per my understanding, while executing the value of L should be [c,d].
My question is:
1. After the second call, L1 is undefined as all the calls as before. And, second and third parameters , both are L. So, why, after second call the control goes to the #line1.?
2. Is my understanding correct in this matter ? "I thought prolog executes the code from left to right. So, as per my understanding, while executing the value of L should be [c,d]."
Thanks in advance...
Please help me out!!
You cannot expect to understand everything that is happening here if you look at it procedurally, because there is too much going on at the same time. This is especially true if you are just beginning to learn the language.
A good approach for learning Prolog is to think declaratively, and ask: What are the conditions that make this hold?
In addition, you are currently writing atoms when you actually mean to write variables. Please correct your post to say for example:
cons(L1, [c|After], [c,d])
Note that After is a variable, and after is an atom.
Now, leaving everything else aside, just consider this single goal in isolation. Try it with:
?- cons(L1, [c|After], [c,d]).
In complete accordance with our expectation, we get the solution:
L1 = [],
After = [d]
Thus, it suffices to understand that this goal can be derived in isolation. Also notice the difference between X = [a] and X = a, which you are currently intermingling.
I'm endeavouring to understand the following Prolog code:
most_probable_hmm_path(Words,Path) :-
probable_paths(Words,[1-[start]],PPaths),
keymax(PPaths,_P-Path1),
reverse(Path1,[start|Path]).
probable_paths([],PPaths,PPaths).
probable_paths([Word|Words],PPaths0,PPaths) :-
findall(PPath,
(outprob(Word,Tag2,PL),
findall(P2-[Tag2,Tag1|Tags],
(member(P1-[Tag1|Tags],PPaths0),
transprob(Tag1,Tag2,PT),
P2 is PL*PT*P1),
AllPaths),
keymax(AllPaths,PPath)),
PPaths1),
probable_paths(Words,PPaths1,PPaths).
keymax(AllPaths,U-V) :-
aggregate(max(N,P), member(N-P,AllPaths), max(U,V)).
It is an implementation of the Viterbi algorithm.
I want to understand how the data structures within the code at various locations are populated, what they look like. Is it possible to intersperse the equivalent of 'print' statements within the algorithm so I can see what is going on at each step? I've often done this when coding in Java or Python and I find it's a more or less useful mechanism to 'grok' the guts of a program.
In case you're interested I've been using it with the following probabilities:
outprob(a,det,0.300).
outprob(can,aux,0.010).
outprob(can,v,0.005).
outprob(can,n,0.001).
outprob(he,pron,0.070).
transprob(start,det,0.30). transprob(v,det,0.36).
transprob(start,aux,0.20). transprob(v,aux,0.01).
transprob(start,v,0.10). transprob(v,v,0.01).
transprob(start,n,0.10). transprob(v,n,0.26).
transprob(start,pron,0.30). transprob(v,pron,0.36).
transprob(det,det,0.20). transprob(n,det,0.01).
transprob(det,aux,0.01). transprob(n,aux,0.25).
transprob(det,v,0.01). transprob(n,v,0.39).
transprob(det,n,0.77). transprob(n,n,0.34).
transprob(det,pron,0.01). transprob(n,pron,0.01).
transprob(aux,det,0.18). transprob(pron,det,0.01).
transprob(aux,aux,0.10). transprob(pron,aux,0.45).
transprob(aux,v,0.50). transprob(pron,v,0.52).
transprob(aux,n,0.01). transprob(pron,n,0.01).
transprob(aux,pron,0.21). transprob(pron,pron,0.01).
And checking the results like so:
?- most_probable_hmm_path([he,can,can,a,can],Sequence).
Sequence = [pron, aux, v, det, n].
go :- match(Mn,Fn),
write('--Matching Result--'),
nl,
write(Mn),
write(' match with '),
write(Fn),
match(Mn1,Fn1).
person(may,female,25,blue).
person(rose,female,20,blue).
person(hock,male,30,blue).
person(ali,male,24,blue).
match(Mn,Fn):-person(Fn,'female',Fage,Fatt),
person(Mn,'male',Mage,Matt),
Mage>=Fage,
Fatt=Matt.
Hi,this is my code...but it's only can show the 1 output...but there are 3 pair of matching in match(X,Y).how to show them all in my go function.
Thank you
You get all your matches if you force backtracking, usually by entering ; (e.g. in SWI Prolog). But you also see that you are getting unnecessary outputs true. This is because the last clause in go is match(Mn1,Fn1). This clause succeeds three times and binds the variables Mn1,Fn1 but then only true is output, because you do not write() after that clause. The fourth time match(Mn1,Fn1) fails and by backtracking you come back to the first clause match(Mn,Fn) that matches, the match is output, etc.
You surely do not want to have this behavior. You should remove the last clause match(Mn1,Fn1) in go. Now by pressing ; you get the 3 matches without any output true in between.
But what you likely want is that the program does the backtracking. To achieve this, you just need to force backtracking by adding false as the last clause. To get proper formatting of the output, use the following program. The last clause go2. is added to get true at the very end.
go2 :- write('--Matching Result--'), nl,
match(Mn,Fn),
write(Mn), write(' match with '), write(Fn), nl,
fail.
go2.
This technique is called failure driven loop.
If you have any predicate that has multiple results and want to to find all of them, you should use findall/3
For example, in your case, you could do something like:
findall([X,Y], match(X,Y),L).
L will be a list that will contain all the X,Y that satisfy match(X,Y) in the format [X,Y].
for example, assuming that:
match(m1,f1).
match(m2,f2).
the result will be L = [ [m1,f1], [m2,f2] ]
note that you can define the format as you wish, for example you could write:
findall(pair(X,Y), match(X,Y), L).
L = [ pair(m1,f1), pair(m2,f2) ]
findall( X, match(X,Y), L).
L = [ m1, m2]
findall( 42, match(X,Y), L).
L = [42, 42]
then you have to recurse on the list to print them.
However, if you wish to find one result, run some code and then continue you could use forall/2:
forall(match(X,Y), my_print(X,Y).
Prolog is a lazy language. Which means that it will stop once it has found a condition that made your problem true. This will be the very first match alone.
IF your code is working (I haven't tried it), then you should try and run the match-statement like this in your prolog inspector: match(X,Y)
The prolog inspector will return all states and print them for you.