Is there a way to turn this:
genre(blues).
gere(hiphop).
genre(rock).
Into something like this:
genre(blues;hiphop;rock).
*I know this does not work, but does something similar to this exist.
You cannot consolidate facts, but you can turn them into a simple rule, like this:
genre(X) :- member(X, [blues, hiphop, rock]).
member/2 is a built-in list predicate in SWI to test list membership.
This lets you apply a predicate across all of the elements of a list, and will succeed only if all applications succeed.
test_list( _, [] ).
test_list( F, [H|T] ) :- P =.. [F,H], P, test_list( F, T ).
You could use this syntax
genre(X) :- X=blues ; X=hiphop ; X=rock.
but personally I advice the member/2 way...
Related
test():-
write("list1"),
read(A),
write("list2"),
read(B),
write(A),
write(B).
append([],X,X).
append([X|Y],Z,[X|W]) :- append(Y,Z,W).'
The output of the code is:
?- test().
list1[A,B,C].
list2|: [D,E].
[_3842,_3848,_3854][_3866,_3872]
true.
But I want it to be as normal Alphabets.
The read predicate is intended for reading terms. For reading strings, use read_string instead.
I have been reading and noticed that predicates like call are called meta-predicates and they can return other predicates as a result (Don't know if return is a good use of the word here) for example here:
assert(call(goal, X,Y)).
Edit: lurker called me to reason, this doesn't work.
I understand that it's not supposed to call predicates functions but is there a way of making assert over a predicate that will be unknown until runtime?
I want to use the same insertion predicate for more than one fact , so assert(fact(X)) does not suit my needs. I can retrieve the fact's name on runtime but how could i use assert without unifying a fact directly?
You should explicitly use assertz/1 or asserta/1. assert/1 is an alias for assertz/1 but only in some Prolog systems.
The call:
assertz(call(goal, X, Y)).
will attempt to assert a fact with functor call. This is what it tries to assert in the database:
call(goal, _, _).
Since call is a functor already defined in Prolog as a predicate, it will generate an error. If you were to assert, say, the following:
assertz(foo(goal, X, Y)).
It would be successful, but what you'd get in the database is something like this:
foo(goal, _, _).
Which doesn't seem very useful. In other words, the assert is just doing what you asked it: asserting a term that you just described whose functor is call or foo in the above cases.
If you want to assert an actual predicate, you just need to use the fact that a predicate is a term whose functor is :-. The general predicate term would be something like Head :- Body or, in canonical form, ':-'(Head, Body). This kind of term can be asserted, as long as at least Head is instantiated before the assertz call.
assertz(':-'(Head, Body)).
Or equivalently (since :- is an operator):
assertz((Head :- Body)).
If I do this:
Head = goal, assertz((Head :- Body)).
I get (using listing/0):
:- listing.
goal :-
call(_).
Not very useful. So Body really should be instantiated before making this assertz/1 call. Here then is another example:
Head = double(X, Y), Body = (Y is X * 2), assertz((Head :- Body)).
Which now results in the following:
:- listing.
double(A, B) :-
B is A * 2.
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.
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...
I need to merge two lists L1=[1,2,3] and L2=[a,b] like this: M=[1,a,2,b,3].
How can I do it in PROLOG please?
you can try
m2([A|As], [B|Bs], [A,B|Rs]) :-
!, m2(As, Bs, Rs).
m2([], Bs, Bs) :- !.
m2(As, [], As).
You may look at this link: Prolog program to merge two ordered lists
This will not give you the output you need, but it is a start.
After some tries, here is the correct answer, much simple than the original proposed by me (tested and working).
mergelist_alternate([],[],[]).
mergelist_alternate([X],[],[X]).
mergelist_alternate([],[Y],[Y]).
mergelist_alternate([X|List1],[Y|List2],[X,Y|List]) :- mergelist_alternate(List1,List2,List).
You can call it like this:
mergelist_alternate([1,2,3],[a,b],L),!.
merge_list([],L,L ).
merge_list([H|T],L,[H|M]):-
merge_list(T,L,M).
It will work. 100% tested!
Input: merge_list([1,2],[3,4],M).
Output: M=[1,2,3,4].