How to insert member list with menu driven prolog program? - list

The Question is-
Write a menu driven PROLOG program to implement various operations on List such as- membership
My ans was -
main :-
nl,
writeln("> Enter a selection followed by a period."), nl,
writeln("> 1. Run a query"), nl,
writeln("> 2. Exit"), nl, nl,
read(Choice),
run_opt(Choice),main.
run_opt(1) :-
writeln("> Enter list"), nl,
read(L),
member(X,[L]).
run_opt(2) :- writeln("Goodbye"), nl.
run_opt(_) :- writeln("Invalid option"), nl.
member(X,[X|_]).
member(X,[_|TAIL]):-
member(X,TAIL).
This above program has problem and i can't insert member with menu driven insertion, like i do this below without menu driven directly--
member(X,[X|_]).
member(X,[_|TAIL]):-
member(X,TAIL).
and the above program correctly executes when i put--
member(X,[1,2,3]).
and it displays members as-
X = 1
X = 2
X = 3
So, i need to do that thing with menu driven but i cant pass the list member in prolog.
Thanks in advance.

Related

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.

How to print all the facts?

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

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
| ?-

Prolog lists and parameters and return values

I'm new to prolog and I just can't figure this out.
I'm trying to build a simple program that receives a list of predicates, searches for a specific predicate in the list, and applies a function to that predicate's parameters.
Something along these lines:
?- program([pred1(a,b,p), pred2(d,b,p), pred2 (a,c,p)]).
program (list1) :-
search(pred2(X,Y,p),list1).
doSomething (X,Y) % with the X and Y returned from search function, both of them.
Basically, I want to use all values that would return from an objective search(pred2(X,Y,p),list1) and use them on another function.
Okay, I tried some stuff in prolog and came to this:
member(X, [X | _]).
member(X, [_ | R]) :- member(X, R).
prog(L1,Out) :- member(pred2(X,Y), L1).
?- prog ([(pred1(a,b),pred2(c,b),pred2(d,a)],Out).
It gives true 2 times as it is supposed to, but I wanted to get Out = [c,b] and Out = [d,a]. How I can achieve this?
Regarding Oak's answer: I get that it isn't a procedural language but I can't figure out how to access values and use them in prolog. Your example wasn't that helpful.
For starters, I would avoiding calling these things "functions". Prolog is not a procedural language, and rules / predicates are not functions.
Basically, when you use a rule you're really asking Prolog, "give me all the values which will satisfy this rule". The rule, by itself, does not return anything.
So say you had the following in a procedural language:
f(g(3))
How would you do it in Prolog? You would need to write some predicate f(X,Y) and some predicate g(X,Y), and then you would need to use the query f(3,Y), g(Y,Z) - which means to ask Prolog to find you values for Y and Z which will satisfy this. Z is what you're interested in.
the best way to approach these filter & project requirements in prolog in my opinion is to write your filter expression such that it takes one argument and succeeds if the input argument passes the filter -
iseven(Num) :- 0 is Num % 2 .
Then write the the projection code as taking one argument that is the input, and one that is the output -
triple(NumIn, NumOut) :- NumOut is NumIn * 3 .
Then tie them together -
triple_evens(NumIn, NumOut) :- iseven(NumIn), triple(NumIn, NumOut).
Then to run this on every member of a list, we should use findall -
triple_evens_in_list(Lin, Lout) :-
findall(Num, ( member(NumL, Lin),
triple_evens(NumL, Num)
), LOut).
This could be generalized to take as arguments the name of the filter & map predicates of course. And it could be compressed down to one stmt too in the form -
findall(Num, ( member(M, List), 0 is M % 2, Num is M * 3 ), ListOut).