How to print all the facts? - list

I am stuck for this problem...
isAt(keys, room3).
isAt(book, room3).
isAt(keys, room6).
isAt(keys, room4).
currently, room3 have keys and book.
I want to print keys and book.
I tried this code and apparently prints only one. (just keys)
look :- isIn(Location),
write('You are in '),
write(Location),
nl,
items_inroom(Location),
nl.
items_inroom(Location) :-
isIn(Location),
isAt(Item, Location),
write('Available Item(s):'),
write(Item),
nl.
items_inroom(_) :-
write('Available Item(s): None'),
nl.
items_inroom is the code that trying to print all these facts.
How can I approach this?
any help will be great! Thank you.

From Chapter 11 in "The Craft of Prolog" by Richard O'Keefe, a bit simplified/refactored to save keystrokes:
print_item_report(Location) :-
( setof(Item, isAt(Item, Location), Items)
-> format("Items available in ~w:~n", [Location]),
forall(member(I, Items),
format("~w~n", [I]))
% print_item_report_footer
; format("No items in ~w~n", [Location])
).
% etc
If you don't have format for whatever reason, you can still use write. If you don't have forall, then this:
forall(Condition, Action)
is defined as
\+ (Condition, \+ Action )
so you can use that instead. See the SWI-Prolog forall/2 documentation for details.

Find all items and display them.
items_inroom(Location) :-
write('Available Item(s):'),
findall(Item, isAt(Item, Location), Items),
show_items(Items).
show_items([]) :-
write('None'), !.
show_items(Items) :-
write(Items).
Actually you can implement the show_items(Items) in any way you want.

items_inroom/1 predicate will always print the first occurrence of Item on all facts isAt/2. You need to loop over all the facts isAt/2, use a metapredicate setof/3, bagog/3 or findall/3, I will recomend setof/3 like #Boris did, or build your own bucle (maybe not the best idea, but it's an option):
show_items(Location):- isAt(Item, Location), % Condition
write(Item), nl, % Process result
fail. % force backtracking to evaluate condition and find a new result
show_items(_). % return true when all options have been evaluated

Related

Converting list of clauses to a query?

let say i have the following facts :
book(65).
own(named('Peter'), 65).
now got the query as a list of clauses :
[what(A), own(named('Peter'), A)]
or
[who(X), book(A), own(X, A)] .
how do I make a rule that accept this list and return the result. Keep in mind that the question could be Why,When,Who...
I went the usual way :
query_lst([]).
%% query_lst([what(Q)|T], Q) :- query_lst(T).
query_lst([H|T]) :- write('?- '),writeln(H),
call(H), query_lst(T).
but this does not allow binding of Q in wh(Q) to the answer which could be in any of the facts that are called by call()
Additional complication I did not forsee is that the query :
(what(A), own(named('Peter'), A).
would fail, because there is no what(X), fact in the DB.
I have to just bind somehow the variable A /that is in what()/ to query_lst(Goals,A) and of course remove what(X) from the list /which i can do with select/3 /
any idea how to bind list-Wh-var to query_lst result ?
my current solution (assumes Q is first element):
query_lst([G|Gs],Res) :- G =.. [Q,Res], member(Q,[what,why,who,when]), lst2conj(Gs,Conj), call(Conj).
Simply convert the list of goals into a conjunction and call it:
list_to_conjunction([], true).
list_to_conjunction([Goal| Goals], Conjunction) :-
list_to_conjunction(Goals, Goal, Conjunction).
list_to_conjunction([], Conjunction, Conjunction).
list_to_conjunction([Next| Goals], Goal, (Goal,Conjunction)) :-
list_to_conjunction(Goals, Next, Conjunction).
Then:
query_list(Goals) :-
list_to_conjunction(Goals, Conjunction),
call(Conjunction).
You got an answer, but it was an answer to your question, not to what you really wanted. Also, you edited your question after you accepted that answer, which isn't very helpful. Typically it's better to open a new question when you have... a new question.
Here is an answer to what you seem to want, which is not exactly what you asked. You have lists of the form [WhPart | Rest] where the WhPart is a wh-word with a variable, and the Rest is a list of goals. You want to execute these goals and get the variable in the wh-term bound.
The good news is that, since the variable in the wh-word also occurs in the goals, it will be bound if you execute them. No extra work is needed. Executing the goals is enough. If the wh-part is really at the start of the list, you can do the whole thing like this:
query([_WhPart | Body]) :-
call_body(Body).
call_body([]).
call_body([Goal | Goals]) :-
call(Goal),
call_body(Goals).
For example:
?- query([who(X), book(A), own(X, A)]).
X = named('Peter'),
A = 65.
?- query([what(A), own(named('Peter'), A)]).
A = 65.
As you can see, there is no need to convert the query to a conjunctive goal: Executing the queries in sequence is exactly the same as executing their conjunction.
Also, it doesn't actually matter which wh-word is used; the only thing that really matters is the variable contained within the term. For this reason the above version does no checking at all, and the _WhPart could be anything. If you want to check that it is a valid term, you can do the following:
query([WhPart | Body]) :-
wh(WhPart),
call_body(Body).
wh(who(_X)).
wh(what(_X)).
wh(when(_X)).
This buys you some "type checking":
?- query([foo(A), own(named('Peter'), A)]).
false.
But not a lot, since you don't know if the wh-word actually fits what is being asked:
?- query([when(A), own(named('Peter'), A)]).
A = 65.

problem with deleting list item in prolog

my code in prolog
:- dynamic kitchenfurniture/1.
kitchenfurniture([furniture(fridge,1), furniture(table,2), furniture(chair,1)]).
writel([H|T]) :- write(H), nl, writel(T).
whatkitchenfurniture :- kitchenfurniture(X), writel(X).
addkitchenfurniture(X) :- kitchenfurniture(Y), append(Y, [X], Z), retract(kitchenfurniture(Y)), assert(kitchenfurniture(Z)).
deletekitchenfurniture(X) :- kitchenfurniture(Y), delete(X, Y, Z), retract(kitchenfurniture(Y)), assert(kitchenfurniture(Z)).
when I enter the code in the console
it does not remove the item from the list
problem wth line code deletekitchenfurniture(furniture(fridge,1)).
It is difficult to understand what exactly you type into the console; why don't you show it?
It is probable that this is wrong:
?- deleteaddkitchenfurniture('furniture(fridge,1)').
The correct way to do it might be:
?- deleteaddkitchenfurniture(furniture(fridge,1)).
No single quotes there. If you put it in single quotes, it becomes an atom with some parentheses embedded in it. If you don't quote, it is a compound term, as in the original list you have in here:
kitchenfurniture([furniture(fridge,1), furniture(table,2), furniture(chair,1)]).

How do I make a new filtered list out of existing list in Prolog?

I'm a very newbie to Prolog and I already need help. I looked up other similar questions but it didn't answer my question.
The problem is;
I have a list of mixed elements [Y, rat, gorilla, 30, mother(alex)]. I want to make a new list out of this with exclusively atoms.
So query should look like this.
?- atoms([Y, rat, gorilla, 30, mother(alex)], Result).
Result = [rat, gorilla].
I tried but I have no idea how to solve this. I think it should be recursive because it needs to check each item weather it's an atom or not.
atoms([], []).
atoms([H | T], Result) :-
atom(H),
append(H, [], Result).
What you want to do is called "filtering" and there is a ready-made "higher-level predicate" for this already. Why "higher level"? Because it doesn't deal in first-order "objects" only, but takes an executable goal that it calls.
Note that this is an eminently functional approach to programming and there is nothing wrong with that: fat chunks of a "logic program" are actually written in functional style. Here we go:
In SWI-Prolog, the predicate that filters is called include/3 or exclude/3.
% atoms/2 filters list Li into list Lo using the predicate atom/1
% This only works in direction Li-->Lo.
atoms(Li,Lo) :- include(atom,Li,Lo).
And a bit of unit test code:
:- begin_tests(filtering).
test("basic test", true(Result = [rat, gorilla])) :-
atoms([Y, rat, gorilla, 30, mother(alex)], Result).
:- end_tests(filtering).
And so:
?- run_tests.
% PL-Unit: filtering . done
% test passed
true.
It works.
Of course, you can always write your own atoms/2 using a recursive call (aka. using an inductive definition)
atoms_i([], []).
atoms_i([H|T], [H|Result]) :- % retain the H in the result list
atom(H), % the "guard" passes if H is atom
!, % then we commit to this branch
atoms_i(T, Result).
atoms_i([H|T], Result) :- % do not retain H in the result list
\+atom(H), % the "guard" passes if H is not atom
!, % then we commit to this branch
atoms_i(T, Result).
People will say that you can leave out the \+atom(H),! in the third clause for efficieny reasons. Although they are right, I find doing that extremely annoying as I prefer symmetry in the source code and cuts that can in principle be removed at a whim. Plus it's about time the compiler start doing some work to find that efficiency itself. It's 2020, not 1980.
Let's add a bit of unit test code:
:- begin_tests(filtering_i).
test("basic test", true(Result = [rat, gorilla])) :-
atoms_i([Y, rat, gorilla, 30, mother(alex)], Result).
:- end_tests(filtering_i).
And so:
?- run_tests.
% PL-Unit: filtering_i . done
% test passed
true.
Good.

Prolog Ancestor with List

I searched around and couldn't find the answer. I'm having trouble making a genealogy list.
So, I have some is_a relations, for example:
is_a(cow, animal).
is_a(calf, cow).
is_a(dog, animal).
.... etc.
I want to have a procedure that does the following:
toAnimal(cow, X).
that outputs
X= [calf, cow, animal].
Basically, if I give it an input(cow), then it will go from cow until animal and add every step to the list.
So far, I have this:
toAnimal(A, B) :- is_a(A,B).
toAnimal(A, B) :- is_a(A, X), toAnimal(X, B).
The output of this is would be
X= cow;
X = animal;
false
How would I get this to become a list?
EDIT:
descend(X,Y) :- is_a(X,Y).
descend(X,Y) :- is_a(X,Z), descend(Z,Y).
toAnimal(X,Y):-
findall(X, descend('animal', X), Y).
I have updated it to this after looking at the suggestion. However, how do I get the list to print? I'm still new to prolog. The findall page said that it would return the list, but it is not doing so for me.
toAnimal(calf, Y)
outputs:
false.
EDIT:
It now returns an empty list. I'm not sure what the issue is here. I have not changed the code at all, so the output should not change but it has.
EDIT:
Thanks MrBratch for the response.
I made the suggested changes, but I now have another issue.
For example,
if I have the relations:
is_a(calf, cow).
is_a(calf, animal).
is_a(cow, cool).
is_a(cool, awesome).
But I ONLY want the path from calf to awesome.
The code will give me the ALL possible paths from calf,x.
For example,
descend(X,Y) :- is_a(X,Y).
descend(X,Y) :- is_a(X,Z), descend(Z,Y).
toAwesome(A,Y) :-
findall(X, descend(calf, X), Y).
will give me a list Y that has
[cow,animal,cool,awesome].
but what I want is
[calf,cow,cool,awesome].
How do I filter the other paths?
and also add the starting point? I suppose I can append calf to the beginning as the head, but how do I ignore the other paths?
EDIT:
Thanks for the help
I figured it out, but I lose the end path and start path. For example,
L contains cow,cool.
But calf and awesome are not there. I tried appending but I don't really understand the syntax. I'm not allowed to do append(X,L,anewlist)?
descend(X,Y) :- is_a(X,Y).
descend(X,Y) :- is_a(X,Z), descend(Z,Y).
toAnimal(A,B) :-
setof(X, (descend(A,X), descend(X,'awesome')), B).
--> append(A, L,anewlist).
?? Is this line not allowed here? How else would I do it? or is there a simpler way to just add it from the beginning
Here it is. (NOTE: you don't need descend predicate to figure out the path of a particular branch of the tree)
is_a(calf, cow).
is_a(calf, animal).
is_a(cow, cool).
is_a(cool, awesome).
path(X,Y,[Z|T]) :- \+ is_a(X,Y), is_a(X,Z), path(Z,Y,T).
path(X,Y,[Y]) :- is_a(X,Y).
find_path(X,Y,[X|L]) :- path(X,Y,L).
Usage:
| ?- find_path(calf,awesome,L).
L = [calf,cow,cool,awesome] ? ;
This sample more or less does what you want:
is_a(cow, animal).
is_a(calf, cow).
is_a(dog, animal).
is_a(snoopy, dog).
is_a(lassie, collie).
is_a(collie, dog).
toAnimal3( X, [X,animal] , animal ):- is_a( X, animal).
toAnimal3( X, [X|R], R ):- is_a( X, Y), toAnimal3(Y, R, _).
:- initialization(main).
main :- toAnimal3( lassie, A, B), write(A), write(B).
When run, this is the output:
[lassie,collie,dog,animal][collie,dog,animal]
Tested it online using this Prolog online interpreter
POST EDIT: Ah, that was it! I should've written "[X,animal]" instead of "[X|animal]" for the first clause! Thanks galore to #mbratch , now the program does exactly what was intended.
toAnimal(X,Y) :- setof(X, descend('animal', X), Y). should do it. Or findall/3.
Info and some examples of bagof, setof, findall.
But remember that you are asking for descend(animal, X) so it won't match the fact is_a(dog, animal) for example, which descend(X, animal) will. You need to make descend to search both sides, or simply be sure that your is_a facts say animal just on left side.
If you want to filter you could do
toAnimal(X,Y) :- setof(X, (descend('animal', X), not(X = animal)), Y).
but you are getting animal as a result because what I mentioned before.

How can I check if an element in the list is an empty list: []?

How can I check if an element in the list is an empty list: [] ?
I've got the following:
display_degrees([A,B,C,D]):- write(B).
display_degrees([A,B,C,D]):- B==[], nl,write('has no degree'), nl, !.
When I enter in something like:
display_degrees([1,[],3,4]).
I just get: [] instead of 'has no degree'. Is my syntax wrong? Can I not add a clause to this predicate like this?
You're getting this behavior because proof search stops when a goal has succeeded. When you type
display_degrees([1,[],3,4]).
the first rule unifies, and it writes B. Since it was a success, it stops. You can ask Prolog to keep searching, and then it will find the second clause. In swipl, I get
?- [foo].
?- display_degrees([1,[],3,4]).
[]
true r % I type 'r' there
has no degree
true.
If you're just learning Prolog, I suggest you avoid the cut operator ! for some time. Also, doing IO is not the most intuitive thing. I would try some exercises with defining things like natural numbers and recursive functions. E.g., plus:
plus(z, X, X).
plus(s(X), Y, s(Z)) :- plus(X, Y, Z).
The problem with what you have is that the more general rule will fire first. You could switch the order:
display_degrees([A,[],C,D]) :- nl, write('has no degree'), nl, !.
display_degrees([A,B,C,D]) :- write(B).
I could just as well have written for the first predicate:
display_degrees([A,B,C,D]) :- B == [], nl, write('has no degree'), nl, !.
But the "shortcut" I show initially is more idiomatic for a Prolog predicate like this.
I kept the cut since you know you deterministically want one choice. The first rule will match if and only if the second list element is [].
| ?- display_degrees([1,[],3,4]).
has no degree
yes
| ?- display_degrees([1,2,3,4]).
2
yes
| ?-