Prolog instantiating variable to a list - prolog

If I have a database such as:
number(0).
number(1).
number(2).
number(3).
number(4).
number(5).
number(6).
number(7).
number(8).
number(9).
and want to write a predicate numbers(L) that instantiates that L to a list of numbers. i.e.
numbers([A,B]).
should instantiate A and B to 10*10 different combinations of numbers, how would I do this. I want to show the recursion in the numbers(L) predicate, not use maplist.
Many thanks for your assistance

First, you should not use number/1 for your purposes, because it is a name of a built-in predicate. Rename number to num or some other name.
A rule that produces a pair of numbers is trivial:
numbers([A,B]) :- num(A), num(B).
Yes, that was really it!
Now you can print all of the combinations like this:
:- numbers([A,B]), write(A), write('-'), write(B), nl, fail.
Here is a demo on ideone.

Related

Representing truth regarding beliefs in prolog

How to make this (or something similar) work in Prolog:
belief(john,red(apple)).
belief(peter,red(apple)).
X :- belief(john,X), belief(peter,X).
And get true. for the following query (while consulting above):-
?- red(apple).
First, it's useful to define a little helper to capture when all (relevant) persons believe something:
all_believe(Belief) :-
belief(john, Belief),
belief(peter, Belief).
Then you can define, for example:
red(Object) :-
all_believe(red(Object)).
green(Object) :-
all_believe(green(Object)).
And with your given set of beliefs you get:
?- red(apple).
true.
?- green(apple).
false.
This works. It requires you to define similar rules for any term that you want to use as a belief.
You can make this a bit shorter with macro definitions using term_expansion:
term_expansion(declare_belief(Belief),
Belief :- all_believe(Belief)).
This means that every top-level definition in your source code of the form declare_belief(Belief) should be treated as if you had written Belief :- all_believe(Belief) instead (with the variable Belief substituted appropriately).
So now you can just write this:
declare_belief(red(_)).
declare_belief(green(_)).
and it will be treated exactly like the longer definitions for red(Object) and red(Object) above. You will still have to write this kind of declaration for any term that you want to use as a possible belief.
Prolog does not allow the head of a rule to be just a variable. The head must be a nonvar term, whose functor (i.e., name and arity) identifies the predicate being defined. So, a possible solution would be something like this:
true_belief(X) :-
belief(john, X),
belief(peter, X).
belief(john, red(apple)).
belief(peter, red(apple)).
Examples:
?- true_belief(red(apple)).
true.
?- true_belief(X).
X = red(apple).

Not in Prolog and use of Bagof

I have database like this:
movie(matrix,wachowski,thriller).
movie(terminator, cameron, thriller).
movie(Gladiator, scott, costume).
movie(star wars, lucas, fantasy).
movie(star trek, abrams, fantasy).
And I want to know who direct fantasy film except Abrams.
I suppose I need to use 'not' predicate, but I don't know exactly how it works.
?- movie(X,not(abrams),fantasy).
But unfortunately it doesn't work.
One more query is what kind of films is not a thriller:
?- movie(X,_,not(thriller)).
Still not working.
Next problem is I need to use predicate direct(Director, listsOfMovie) based on bagof.
?- direct(Director, listsOfMovie) :- bagof(Director,movie(Director,listsOfMovie,_), listsOfMovie).
Still without success :(
Anyone can help?
Use of not
You can't use Prolog predicates like functions. not/1 is a predicate which accepts a query as an argument. So this isn't doing what you think:
movie(X,not(abrams),fantasy).
This is querying movie with a second argument of not(abrams). You don't have any facts or predicates that match movie(_, not(_), _) so it will always fail.
If you want to know which films were not thrillers, you might render it:
movie(X, _, Type),
Type \= thriller.`
Using not, it might be:
not( movie(X, _, thriller) ).
If you wanted the syntax of movie(_, not(_), _) to work, you could write a predicate for it:
movie( Name, not(Director), Type ) :-
movie(Name, D, Type),
D \= Director.
Now we have either a fact or a predicate head that matches the form, movie(_, not(_), _), and then the query, movie(X, not(abrams), Y) would work. But it's not normally done this way.
Using bagof/3
Let's look at your use of bagof. In the simplest case, bagof is supposed to take three arguments:
bagof(X, {query involving X}, ListOfSatisfingXs)
So bagof will run the {query involving X} generating each X that makes it true, creating ListOfSatisfingXs, a unique, sorted list of such instantiations of X. In other words, ListOfSatisfingXs is the unique, sorted values of X that make {query involving X} succeed.
In your case, you've gotten the arguments to bagof a bit mixed up:
direct(Director, listsOfMovie) :-
bagof(Director, movie(Director, listsOfMovie, _), listsOfMovie).
Here, you're reusing your Director argument as your bagof argument, which is not good (since it's not intended). Since you're looking for a list of movies, the first argument should represent the movie. Your query to movie is using listsOfMovie, your intended target argument to hold the list result, which it shouldn't. And finally, listsOfMovie is an atom, not a variable, since it doesn't start with a capital letter.
The corrected version would be:
director_movies(Director, ListOfMovies) :-
bagof(Movie, movie(Director, Movie, _), ListOfMovies).
Here, the bagof is getting the *Unique, sorted list of Movie values such that movie(Director, Movie, _) is true and providing that resulting list in ListOfMovies.

Prolog: find a supplier who supply all parts

I'm new to Prolog. These are my facts.
part_cost(Part, Supplier)
part_cost(top_tube ,cinelli).
part_cost(top_tube ,columbus).
part_cost(down_tube ,columbus).
part_cost(head_tube ,cinelli).
part_cost(head_tube ,columbus).
part_cost(seat_mast ,cinelli).
part_cost(seat_mast ,columbus).
I want to find a supplier who supplies all kinds of parts, which is actually columbus.
I don't know how to say "all" in Prolog language.
Any help is appreciated.
Update
Thank you, #Ankur and #Sergey Dymchenko. Your list approach inspired me! I can write rules:
supplyAllParts(Supplier, []):-true.
supplyAllParts(Supplier, [Part|PartRest]) :-
part_cost(Part, Supplier, _, _),
supplyAllParts(Supplier, PartRest).
and call it by
?- supplyAllParts(S,[top_tube, down_tube, head_tube, seat_mast]).
S = columbus.
Now can Prolog dynamically find the part list ([top_tube, down_tube, head_tube, seat_mast]) from the facts rather than I manually provide it?
supplies([],_).
supplies([H|T],S) :- part_cost(H,S), supplies(T,S).
| ?- setof(P,S^part_cost(P,S),R), supplies(R,Supplier).
R = [down_tube,head_tube,seat_mast,top_tube]
Supplier = columbus
First, you probably need to define a notion of "all parts" manually, because maybe there is some kind of "bottom_super_gravitsapa", that no one has:
% store in sorted order, to compare with setof results later
sort([top_tube, down_tube, head_tube, seat_mast], AllParts)
To get a list of all parts for every supplier we can use setof/3:
?- setof(Part, part_cost(Part, Supplier), Parts).
setof(Part, part_cost(Part, Supplier), Parts).
Supplier = cinelli
Parts = [head_tube,seat_mast,top_tube] ?;
Supplier = columbus
Parts = [down_tube,head_tube,seat_mast,top_tube]
yes
And now just add a condition that list of parts for a specific supplier and AllParts are the same:
Parts == AllParts
If you don't want to define AllParts manually and assume that there is a supplier for every possible part, you can use another setof to get AllParts from the facts before the main setof.
all is a big word, in any language, and what it means varies so much... Down to the earth , in Prolog we have findall/3 family, that outputs a list with all patterns we instruct to extract from succeeded queries. The output list then is further processed ... But for your case, library(aggregate) is more handy:
supplies_all(Supplier) :-
aggregate(max(N,S), count_part_cost(S,N), max(_, Supplier)).
count_part_cost(S,N) :-
aggregate(count, P^part_cost(P,S), N).
I used a service predicate count_part_cost/2, just to keep the main one clear...
If you try to 'inline' them, beware to variables usage. Study variables quantification until you are comfortable with it.
edit As noted by Sergey, my code is not correct. Here is my bet for a more appropriate definition:
supplies_all(Supplier) :-
setof(P, S^part_cost(P,S), Ps),
setof(P, part_cost(P,Supplier), Ps).
I think it highlights well what I intended above recommending about studying variable quantification...
edit another possible definition, less costly but with redundant multiple solution (well, we have setof for that...)
supplies_all(Supplier) :-
% peek any Supplier from catalog
part_cost(_,Supplier),
% check it has all parts available
forall(part_cost(P,_), part_cost(P,Supplier)).

Prolog program with lists and sublists

Hi I have to solve a problem in Prolog, that sounds like this: deletes all the sublists of a list that are increasing. For example the list [1,[2],[3,4],6] becomes [1,6].
So far I have tried this but it's not working. Any help please ?
domains
el=integer
list=el*
element=integer;list
lista=element*
goal
elim([1,[2],[3],4)],L),
write(L).
predicates
elim(lista,lista)
is_increasing(lista)
is_list(lista)
clauses
is_increasing([A,B|T]) :-
B>A,
is_increasing([B|T]).
is_list([_|_]).
is_list([]).
elim([],[]).
elim([E|Es],[E|Ts]) :-
is_list(E),
is_increasing(E),
elim(Es, Ts).
attempt to modularize your code: first write an is_increasing/1. Since it appears that a list of 1 element is increasing, you can do as simply as
is_increasing([A,B|T]) :- B > A, is_increasing([B|T]).
is_increasing([_]).
then you can use it to discard elements while copying. Beware to check that an element is a list before calling. Here is a possible definition
is_list([_|_]).
is_list([]).
edit
there is a bad declaration, as advised by mbratch
element=i(integer);l(list)
should be
element=integer;list
Also, you forgot is_increasing([_])., and anyway you're not using at all is_list or is_increasing.
The rule eliminating sublists of course should read
elim([E|Es], Ts) :- is_list(E), is_increasing(E), elim(Es, Ts).
just add the base case and a copy. i.e. elim is a 3 clauses predicate...
edit apart the rule above, you need only a base case
elim([],[]).
and a copy
elim([E|Es],[E|Ts]) :- elim(Es, Ts).
just try to understand why the order of rules is also important in Prolog...

Convert list into functor parameter

I got stuck to implement a logic. At some instance in my program I have a list say named as List.
The length of this List is variable and I don't know in advance. Now I have to pass this list in a functor to create a fact and I am unable to implement it. For eg:
if List is [first] then it should add the fact functor(first).
if List is [first,second] then it should add the fact functor(first,second).
if List is [first,second,third] then it should add the fact functor(first,second,third).
and so on...
I was trying by =.. but here I am unable to map that variable length constraint. For fixed length I am able to perform but I don't know in advance that how many elements will be there in list.
Any suggestions to implement this logic. Thanks.
I don't quite understand your problem with =.. but this worked for me:
assert_list(List) :-
Term =.. [my_functor|List],
assert(Term).
Note that I use my_functor instead of simply functor because functor/3 is a built-in predicate so you cannot assert ternary functor facts (functor(first, second, third)).
Calling it:
?- assert_list([first,second,third]).
true.
Checking that it works:
?- listing(my_functor).
:- dynamic user:my_functor/3.
user:my_functor(first, second, third).
true.
Note that technically, the different n-ary my_functor/n predicates are not the same predicates. You must use different queries in your program for each n. To circumvent this, you could simply assert the list as one and only argument of my_functor:
?- List = [first, second, third],
assert(my_functor(List)).
true.
?- listing(my_functor).
:- dynamic user:my_functor/3.
user:my_functor([first, second, third]).
true.
My SWI-Prolog version is 5.7.5.

Resources