prolog predefined lists search - prolog

I'm new to and just started writing prolog code I'm not sure how list of lists works and how to write rules for already defined lists, when I enter run_tests. below test cases should be executing
Below is the project I am working on, could anyone help me getting started on this?
employees([ employee(tom, 33, cs, 85000.00),
employee(joan, 23, ece, 110000.00),
employee(bill, 29, cs, 69500.00),
employee(john, 28, me, 58200.00),
employee(sue, 19, cs, 22000.00)
]).
dept_employees(Employees, Dept, DeptEmployees) :-
'TODO'(Employees, Dept, DeptEmployees).
:- begin_tests(dept_employees, []).
test(dept_employees_cs, all(Zs =
[[ employee(tom, 33, cs, 85000.00),
employee(bill, 29, cs, 69500.00),
employee(sue, 19, cs, 22000.00)
]])) :-
employees(E),
dept_employees(E, cs, Zs).
test(dept_employees_ece, all(Zs = [[ employee(joan, 23, ece, 110000.00) ]])) :-
employees(E),
dept_employees(E, ece, Zs).
test(dept_employees_ce, all(Zs = [[]])) :-
employees(E),
dept_employees(E, ce, Zs).
:- end_tests(dept_employees).

Related

Some problems with reading file

I used some prolog codes for reading file numbers to list, reading is working, i cannot use list that contains readed numbers.
my_representation(Codes, Result) :-
atom_codes(Result, Codes).
stream_representations(Input, L) :-
read_line_to_codes(Input, Line),
( Line == end_of_file
-> L = []
;write("stream myrepresant oncesi Line="),writeln(Line),
write("stream myrepresant oncesi FinalLine="),writeln(FinalLine),
my_representation(Line, FinalLine),
stream_representations(Input, FurtherLines).
main :-
stream_representations(Input, L),
close(Input).
Actually, the call stream_representations(Input, L) instantiates the variable L to the atom '1,2,3,4', as can be seen with the following query:
?- my_representation([49, 44, 50, 44, 51, 44, 52], L).
L = '1,2,3,4'.
In order to obtain the desired result, you could modify the predicate my_representation as following:
my_representation(Codes, Result) :-
atom_codes(Atom0, Codes), % obtain Atom0 = '1,2,3,4'
format(atom(Atom1), '[~w]', Atom0), % obtain Atom1 = '[1,2,3,4]'
read_term_from_atom(Atom1, Result, []). % transform atom '[1,2,3,4]' into list [1,2,3,4]
Now, we have:
?- my_representation([49, 44, 50, 44, 51, 44, 52], L).
L = [1, 2, 3, 4].
[EDIT]
You can modify your program to use this new version of the predicate my_representation as following:
main :-
open('test.txt', read, Input),
stream_representations(Input, Codes),
close(Input),
my_representation(Codes, List), % <= call new version only here
writeln('list read': List),
forall(append(Prefix, Suffix, List),
writeln(Prefix - Suffix)).
stream_representations(Input, L) :-
read_line_to_codes(Input, Line),
( Line == end_of_file
-> L = []
; append(Line, FurtherLines, L), % <= just append line to further lines
stream_representations(Input, FurtherLines),
writeln('Stream represention': L) ).
my_representation(Codes, Result) :-
atom_codes(Atom0, Codes),
format(atom(Atom1), '[~w]', Atom0),
read_term_from_atom(Atom1, Result, []).
Result:
?- main.
Stream represention:[49,44,50,44,51,44,52]
list read:[1,2,3,4]
[]-[1,2,3,4]
[1]-[2,3,4]
[1,2]-[3,4]
[1,2,3]-[4]
[1,2,3,4]-[]
true.

About a Prolog tokenizer

One of my assignments ask us to build a prolog tokenizer. Right now I wrote a predicate that can change space and tab it new line. But I don't know how to implement that into the main program.
The replace part looks like this:
replace(_, _, [], []).
replace(O, R, [O|T], [R|T2]):- replace(O, R, T, T2).
replace(O, R, [H|T], [H|T2]) :- H \= O, replace(O, R, T, T2).
And the Main part has a predicate called removewhite(list1 list2)
So how can I let removewhite execute replace?
You are a bit 'off trail' toward a tokenizer: removewhite/2 isn't going to buy you any useful functionality. Instead, consider a DCG (of course if your Prolog offers this functionality):
tokenize(String, Tokens) :- phrase(tokenize(Tokens), String).
tokenize([]) --> [].
tokenize(Tokens) --> skip_spaces, tokenize(Tokens).
tokenize([Number|Tokens]) --> number(Number), tokenize(Tokens).
skip_spaces --> code_types(white, [_|_]).
number(N) --> code_types(digit, [C|Cs]), {number_codes(N,[C|Cs])}.
code_types(Type, [C|Cs]) --> [C], {code_type(C,Type)}, !, code_types(Type, Cs).
code_types(_, []) --> [].
despite the simplicity, this is a fairly efficient scanner, easily extensible.
In SWI-Prolog, that has (non ISO compliant) extensions for efficient handling of strings, this can be called from top level like:
?- tokenize(`123 4 567 `, L).
L = [123, 4, 567]
or
?- atom_codes('123 4 567 ',Cs), tokenize(Cs, L).
Cs = [49, 50, 51, 32, 32, 52, 32, 53, 54|...],
L = [123, 4, 567]
Btw, in SWI-Prolog, number//1 is predefined (with much more functionality, of course) in library(dcg/basics).
Anyway, about your question
how can I let removewhite execute replace?
I feel you're really 'barking the wrong tree': removing a space - that actually is a separator - will mess up your input...
You can write a more "powerfull" predicate
replace_all(_, _, [], []).
replace_all(L, R, [X|T], [R|T2]):-
member(X, L),
replace_all(L, R, T, T2).
replace_all(L, R, [X|T], [X|T2]) :-
\+ member(X, L),
replace_all(L, R, T, T2).
Then, you will have
removewhite(List1, List2) :-
remove_all([' ', '\t'], '\n', List1, List2).

Working with lists of lists in Prolog

New to prolog, trying to get my head around dealing with lists of lists recursively.
Say I have a list:
prices([20, 20, 40]).
And another list (of lists):
items([ [12, 14, 23],[8, 16, 22],[18, 12, 14] ]).
I want to append an element from prices to each list in items:
items([ [12, 14, 23, 20],[8, 16, 22, 20],[18, 12, 14, 40] ]).
I'm having trouble with working through both a single list and a list of lists at the same time.
Any pointers would be appreciated.
Thanks!
It's not too difficult if you sort it out in its appropriate pieces. In prolog, a list is a list until you need to do something with an element.
item_prices(ItemPrices) :-
prices(Prices),
items(ItemLists),
item_prices(ItemLists, Prices, [], ItemPrices), !.
item_prices([ItemList|ItemLists], [Price|Prices], SoFar, ItemPrices) :-
append(ItemList, [Price], ItemPrice), % Assumes the items are lists, price is not
item_prices(ItemLists, Prices, [ItemPrice|SoFar], ItemPrices).
item_prices(_, _, ItemPrices, ItemPrices).
Then you'd just call:
item_prices(ItemPrices).
To give:
ItemPrices = [[18,12,14,40],[8,16,22,20],[12,14,23,20]]
any time you have difficulty in dealing with too much stuff at the same time, see if you can separate your concerns and deal with each separately, through an auxiliary predicate.
For instance here you could define add_to_end( Element, List, Newlist) and use it in your main predicate.
add_to_end( E, [], R):- R = ... .
add_to_end( E, [A|B], R):- R=[A|X], add_to_end( E, B, ...).
When you've mastered the basics of the language, do see what's there in the library; chances are there's already a predicate that lets you append two lists, which you could use somehow instead of writing your own specialized version of it. After all, add_to_end( E, L, R) == append_two_lists(L, [E], ...).
this is a variation on mbratch answer
item_prices(ItemPrices) :-
prices(Prices),
items(ItemLists),
item_prices(ItemLists, Prices, ItemPrices), !.
item_prices([ItemList|ItemLists], [Price|Prices], [ItemPrice|ItemPrices]) :-
append(ItemList, [Price], ItemPrice), % Assumes the items are lists, price is not
item_prices(ItemLists, Prices, ItemPrices).
item_prices([], [], []).
without an accumulator, we avoid to reverse the order.
Here is a solution, using maplist/3, handy when you must perform the same operation among matched lists elements:
items_updated(Us) :-
items(Is),
prices(Ps),
maplist(append_, Is, Ps, Us).
append_(Is, P, R) :- append(Is, [P], R).

Delete vowels in a list

Write a program that deletes vowels (String, NoVowelsString) that deletes all vowels from a given string.
So far I've got the condition vowel(X):- member(X,[a,e,i,o,u]). Then I thought of the one that deletes all the elements from the other list:
delete2([],L1,L1).
delete2([H|T],L1,L3) :-
delete2(H,L1,R2),
delete2(T,R2,L3).
So having these two I thought that I could put a condition to those elements being deleted that they have to be a member of [a,e,i,o,u]. Though I still haven't got anywhere.
The following is based on the reification of term equality/inequality.
First, we first define list_memberd_t/3, which behaves just like the memberd_truth/3 but has a different argument order:
list_memberd_t([] ,_,false).
list_memberd_t([Y|Ys],X,Truth) :-
if_(X=Y, Truth=true, list_memberd_t(Ys,X,Truth)).
list_memberd_truth(Xs,X,Truth) :- list_memberd_t(Xs,X,Truth).
For the sake of brevity, let's define memberd_t/3 based on list_memberd_t/3:
memberd_t(X,Xs,Truth) :- list_memberd_t(Xs,X,Truth).
As a parallel to library(apply), let's define tinclude/3:
:- meta_predicate tinclude(2,?,?).
tinclude(P_2,Xs,Zs) :-
list_tinclude_list(Xs,P_2,Zs).
list_tinclude_list([], _P_2,[]).
list_tinclude_list([E|Es],P_2,Fs0) :-
if_(call(P_2,E), Fs0 = [E|Fs], Fs0 = Fs),
list_tinclude_list(Es,P_2,Fs).
tfilter/3 is another name for tinclude/3:
tfilter(P_2,As,Bs) :-
tinclude(P_2,As,Bs).
Next, we define the meta-predicate texclude/3, the opposite of tinclude/3:
:- meta_predicate texclude(2,?,?).
texclude(P_2,Xs,Zs) :-
list_texclude_list(Xs,P_2,Zs).
list_texclude_list([],_,[]).
list_texclude_list([E|Es],P_2,Fs0) :-
if_(call(P_2,E), Fs0 = Fs, Fs0 = [E|Fs]),
list_texclude_list(Es,P_2,Fs).
Now let's use them together!
?- texclude(list_memberd_truth([a,e,i,o,u]),
[d,e,l,e,t,e,' ',v,o,w,e,l,s,' ',i,n,' ',a,' ',l,i,s,t], Filtered).
Filtered = [d, l, t, ' ',v, w, l,s,' ', n,' ', ' ',l, s,t].
Edit
As an alternative to using above texclude/3, let's use tinclude/3 with an auxiliary predicate not/3 to flip the truth value:
:- meta_predicate not(2,?,?).
not(P_2,X,Truth) :-
call(P_2,X,Truth0),
truth_flipped(Truth0,Truth).
truth_flipped(true,false).
truth_flipped(false,true).
Sample query:
?- tinclude(not(list_memberd_truth([a,e,i,o,u])),
[d,e,l,e,t,e,' ',v,o,w,e,l,s,' ',i,n,' ',a,' ',l,i,s,t], Filtered).
Filtered = [d, l, t, ' ',v, w, l,s,' ', n,' ', ' ',l, s,t].
here a solution using DCG. Note how the 'output' is obtained (no arguments passing, only difference lists)
novowels --> ("a";"e";"i";"o";"u"), !, novowels.
% or ..
% novowels --> [C], {memberchk(C, "aeiou")}, !, novowels.
novowels, [C] --> [C], !, novowels.
novowels --> [].
I must confess the second cut doesn't like me, but seems required.
test:
?- phrase(novowels, "abcdefghilmnopq", L),format('~s',[L]).
bcdfghlmnpq
L = [98, 99, 100, 102, 103, 104, 108, 109, 110|...].
edit About the second cut, it seems required by 'left hand' notation: if I code with argument, without cut, I get a correct parsing:
novowels(Cs) --> ("a";"e";"i";"o";"u"), !, novowels(Cs).
% novowels(Cs) --> [C], {memberchk(C, "aeiou")}, !, novowels(Cs).
novowels([C|Cs]) --> [C], novowels(Cs).
novowels([]) --> [].
test:
?- phrase(novowels(L), "abcdefghilmnopq"),format('~s',[L]).
bcdfghlmnpq
L = [98, 99, 100, 102, 103, 104, 108, 109, 110|...] ;
false.
I wonder if this is a bug of the DCG translator, or (more probably) my fault...
Here is the code
deleteV([H|T],R):-member(H,[a,e,i,o,u]),deleteV(T,R),!.
deleteV([H|T],[H|R]):-deleteV(T,R),!.
deleteV([],[]).
What it does?
First it question itself?It's the head a vowel
Yes->We ignore it.
No->We need it.
If it finds an empty list, it constructs the result list, and when returning from backtracking it appends the consonats in front.
This code was tested in SWIProlog.

Prolog Negation

I am trying to solve a simple query in Prolog that uses negation but I can't crack it. The query is "Find the categories that have never been sold".
The knowledge base is as follows:
category(stationery, 30, 200, 10, 2).
category(books, 10, 30, 3, 2).
category(consumables, 50, 300, 15, 3).
item(pen, stationery, 10, 150).
item(colgate_small, consumables, 20, 65).
item(colgate_medium, consumables, 45, 70).
item(colgate_big, consumables, 70, 34).
item(juice_small, consumables, 45, 23).
item(juice_medium, consumables, 60, 23).
item(juice_big, consumables, 80, 12).
item(book, stationery, 5, 65).
item(pencil, stationery, 7, 56).
item(newspaper, books, 50, 400).
sale(tom, 1/1/07, pen, 3).
sale(peter, 1/1/07, book, 85).
sale(peter, 1/1/07, juice_small,1).
sale(alice, 7/1/07, pen, 10).
sale(alice, 7/1/07, book, 5).
sale(patrick, 12/1/07, pen, 7).
Sam Segers answer is correct, though it will give you the list of categories not sold.
If you don't want an aggregation but rather a predicate which will backtrack over all the categories which do not have any items sold you would write something like this:
not_sold(Cat):-
category(Cat,_,_,_,_), % Get one category at a time
\+ ( % Applies negation
item(Item, Cat,_,_), % Check for items in this category
sale(_,_,Item,_) % Has the item been sold ?
).
This predicate, upon backtracking, will yield all the categories for which no items where sold.
Might not be the most efficient way.
not_sold(Cats) :-
findall(Y,(sale(_,_,X,_),item(X,Y,_,_)),Sold),
findall(C,(category(C,_,_,_,_),not(member(C,Sold))),Cats).
But I think it should work.
Are you aware of Prolog's negation-as-failure (control) predicate, \+/1? It is true iff the goal cannot be proven.
Using the predicate, the task reduces to finding categories that have been sold, i.e.
is_category(C) :- category(C, _, _, _, _).
sold_category(C) :-
is_category(C),
item(I, C, _, _),
sale(_, _, I, _).
and
unsold_category(C) :- is_category(C), \+ sold_category(C).
If you want a list of all those categories, simply use the findall predicate.
findall(C, unsold_category(C), L).
As Sam Segers mentioned you can put a not() around an expression.
You can also use the \+ operator to logically negate a predicate:
removeItem([Head|Tail], Head, Tail).
removeItem([Head|Tail], Item, [Head|Tail2]) :-
\+(Head = Item),
removeItem(Tail, Item, Tail2).
not_sold(Cats) :-
findall(C, (
category(C, _, _, _, _),
\+ (
item(I, C, _, _),
sale(_, _, I, _)
)
), Cats).
Usage:
?- not_sold(Cats).
Cats = [books].

Resources