Prolog (Sicstus) - setof and findall combination issues - prolog

Given a set of routes a given station has, such us :
route(TubeLine, ListOfStations).
route(green, [a,b,c,d,e,f]).
route(blue, [g,b,c,h,i,j]).
...
I am required to find names of lines that have a specific station in common. The result must be ordered, with non-repeated stations and must return an empty list, if there were no results. So, querying
| ?- lines(i, Ls).
Should give:
Ls = [blue,red,silver] ? ;
no
I tried doing the following:
lines(X, L) :- setof(L1, findall(W, (route(W, Stations),member(X, Stations)),L1), L).
However, it gives the following as an answer:
Is = [[blue,silver,red]];
no
So unordered with double braces. I tried using just findall, but the result is not ordered. I know I could then write sort function and pass that through, however I was wondering if it is possible to use just findall and setof in this instance?

Actually, it's easier than your attempt, but you need to grasp the peculiar setof' behaviour wrt free variables, and account for the eventuality that an unknown station was required (setof/3 fails if there are no solutions).
lines(X, Ls) :-
setof(L, Stations^(route(L, Stations), member(X, Stations)), Ls)
-> true ; Ls = [].
An easier alternative, as you said, use findall/3 exactly as you're doing (without setof!), and sort the output.

Related

Array Univ var ([x,y]=..T) - prolog

I saw a question asking what does [a,b,c]=..L. return.
When testing this I saw that it returns: L = ['.', a, [b, c]].
I can't understand why this happens, I was unable to understand the nature of Univ from the documentation. Understanding this will help me understand Univ.
One way to learn more about terms is to use write_canonical/1 in a conforming Prolog system.
For example, with GNU Prolog, we obtain:
| ?- write_canonical([x,y]).
'.'(x,'.'(y,[]))
This shows:
the primary functor in this term is '.', with arity 2
the first argument is x
the second argument is '.'(y, []), which is the list [y]
This explains why (=..)/2 yields:
| ?- [x,y] =.. Ls.
Ls = ['.',x,[y]]
and also your other example.
This happends because representation of the list in prolog is a tree datastructure,like this.It's top node is a "dot" left side is Head then again a dot on right if tail is not empty and head on left hand side and "dot" on right handside. When you do this you are simply creating a predicate(well , not exact a predicate but it is sometimes needed as i show an example): suppose i write:
V=..[somefunctor,X,Y,Z]
Then it will automatically construct a predicate like this:
somefunctor(X,Y,Z).
Now Why do we need this? Supppose i call a predicate with these terms: predicate(somefunctor,term,term2,term3) and predicate or rule looks something like this: predicate(X,Y,Z,T) and i ask you that no matter what predicate is in X, you have to call this predicate with parameters Y,Z,T. May be you think you call that predicate by writing like this: X(Y,Z,T) but unfortunately it is not allowed in prolog, so here you can use V=..[X,Y,Z,T] where X should be placed as first argument because it's predicate name and as a result you get something like this: V = somefunctor(term,term2,term3) and this happends internally. In order to invoke this predicate you make use of call predicate:
call(V) where `call/1` is a metapredicate and `V=..` is a not logical predicate.

Pattern-matching: query returns 'no' even when base case provided

I have a simple Prolog-program that I need some help debugging.
The point is to extend the program by pattern-matching to create a proof checker for propositional logic. The problem I have is that I get no when I expect yes and my 'fix' (providing a base case for valid_proof_aux) still gives me two solutions and I don't know why.
Not sure how to go about debugging Prolog yet, sorry.
%call:
valid_proof([p],p,[[1, p, premise]])
%src:
reverse_it([],Z,Z).
reverse_it([H|T],Z,Acc) :- reverse_it(T,Z,[H|Acc]).
valid_proof(Prems,Goal,Proof):-
last(Proof, [_, Goal, _]),
reverse_it(Proof, RevP, []),
valid_proof_aux(Prems, RevP) .
valid_proof_aux(Prems,
[[_,Prop,premise] | T]):-
memberchk(Prop,Prems),
valid_proof_aux(Prems,T).
%my 'fix'
valid_proof_aux(_, []) :- true .
You don't really show how to run the program and what exactly you get (you should edit your question with and add this), so this answer is a bit of a guess, but anyway:
You need the base case either way (as you observe yourself), valid_proof_aux/2 would fail when the list becomes empty [] and does not match [[...]|T] anymore.
?- [] = [_|_]. % try to unify an empty list with a non-empty list
false.
What you need to do to get rid of the choice point is to put the list argument as the first argument.
valid_proof_aux([], _).
valid_proof_aux([[_,Prop,premise]|T], Prems) :-
memberchk(Prop, Prems),
valid_proof_aux(T, Prems).
Note that you don't need the :- true., this is implicit. Also, avoid leaving any blanks on the two sides of the | in [Head|Tail].

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