Prolog: Use generated List in another Predicate - prolog

I'm a complete Prolog beginner, and I'm kinda lost when it comes to using a list generated by a rule in another rule.
Specifically, I have this rule:
all_stations(Line,Stations) :-
findall(S, station(Line,S), Stations).
which generates a list with the name Stations when given a valid Line.
My question is, how can I use this specific list Stations in another rule that I made:
all_conn([Station]) :- conn(Station).
all_conn([HeadStation|Rest]) :- conn(HeadStation), all_conn(Rest).
which checks using recursion that all members of the provided list fulfill a specific requirement?
This is a pretty fundamental question, so I haven't tried anything else.

Related

Prolog Predicates Exam Questions

I'm studying for an Artificial Intelligence exam and struggling to understand how to answer certain questions focusing on Predicates. The two questions in particular are:
Define a predicate which behaves as follows -
?- stage_name(billie, Name).
Name = rose
yes
?- stage_name(jenna,Name).
Name = clara
yes
Write a predicate that takes two argument and is true if both actors are on the same show. Thus
?-same_show(david,clara).
is true, whilst
?-same_continent(elisabeth,skippy).
is not
I don't really understand how I would answer these questions, and I'm finding very little Prolog information online. I would appreciate some help. Apologies for the formatting.
1:
stage_name(billie,rose).
stage_name(jenna,Name) :- Name=clara.
Explanation:
Given a query, Prolog looks for an appropriate predicate according to the input parameters and the name and "executes" it. The result is either true/false if no output parameter is given. In this case there is one (Name) which can be seen from the leading capital letter. Note that there are two possible ways to implement this. The former is probably the most common (predicates of this form are called "facts" whereas predicates such as the lower are called "rules").
2:
As mentioned in my comment, I don't really understand the connection between the two given predicates. Also it feels like there is something missing such as a facts that determine which person is on which show...
Assuming such facts are missing, I would write the Prolog program as follows:
onShow(david, s1).
onShow(clara, s1).
onShow(bernie, s2).
same_show(P1, P2) :- onShow(P1,X), onShow(P2,X).
Explanation:
The predicate is only true if both P1 and P2 visit the same show X.
Hints:
A "comma" represents a logical AND operator. Having different rules with the same name and parameter count represents logical OR. Edit: As Boris mentioned in a comment, this is not exactly true. This association simply helped me to understand the connection between "Logical Predicates" and "Prolog Predicates".
Visit SWISH to test your Prolog programs.

How do I find the highest number from the database in PROLOG for a specified person?

I have been assigned to do some work on PROLOG, I have made a very good attempt at one question where I was suppose to find the largest number of pages for a single article by a certain author.
What I have so far is:
A= Author
P = Pages
Pages(A,N) :- Database(A,_,_,_,N,_).
getpages(X) :- findall(A,pages(_,A),X).
getauthor(X) :- findall(A,pages(A,_),X).
printlist([A|N]) :- print(A), nl,pages(A,N).
Once I run a query for findall I get the numbers of pages but not in descending order, showing the highest value, how do I do that?
I have an idea of using sumlist and/or printlist somehow.
Also how do I find something in a database Starting with 'abc' or whatever.. I know in sql you have a function to do that, but how is it done in PROLOG? I want to find all the articles starting with 'IEEE'.
If you are wondering how to print a list in ascending order, you just have to sort it first. There is a builtin predicate, sort/2, that you can use for sorting a list in ascending order.
Check the SWI-Prolog documentation for details. If there are possible duplicates that you don't want to eliminate, use msort/2 instead.
You could write a predicate that gets the pages in ascending order like this:
getpages_sorted(X) :- findall(A, pages(_, A), Unsorted), sort(Unsorted, X).
It would also be wise to choose representative names for your variables, code clarity plays an integral part at debugging in prolog.
setof/3 instead of findall/3 will do, but you have to qualify free variables scope to properly use it, since variables binding plays a very important role in Prolog execution:
getpages(X) :- setof(A,S^pages(S,A),X).
library(aggregate) will put in your hands more constructs ready to use, similar to what's available in SQL, but you should first try to understand well setof/3.
Prolog doesn't have 'select ... where ... LIKE ...'. Symbols are used for identity, while in SQL (intended as relational calculus), identity is by record. This is a shortcoming when moving logic from relational RDBMs to Prolog, similar to the case insensitiveness that RDBMs implement. A COLLATION it's not a concept of Prolog...
So, when you ask
how do I find something in a database Starting with 'abc' or whatever..
you should implement your own matching algorithm, for instance
page(Author, _Title) :- sub_atom(Author,_,_,_,abc).
would match any page having 'abc' in Author atom, similar to
select Author from page where Author like '%abc%'
edit sub_atom/5 it's rather powerful: for instance, to peek atoms starting with abc
1 ?- sub_atom(abcd,0,_,_,abc).
true.
2 ?- sub_atom(zabcd,0,_,_,abc).
false.

Prolog recursion and building output from recursive calls

I am learning Prolog via http://www.learnprolognow.org and I am having some trouble understanding how to recursively build up a variable with results from another recursive call, as per Practical Session 3.4, question 3. The initial problem is a straight-forward recursive call to determine if a route is feasible. But the follow-on problem asks you to show the actual path to get to the end of the route.
We are given the following knowledge base of travel information:
byCar(auckland,hamilton).
byCar(hamilton,raglan).
byCar(valmont,saarbruecken).
byCar(valmont,metz).
byTrain(metz,frankfurt).
byTrain(saarbruecken,frankfurt).
byTrain(metz,paris).
byTrain(saarbruecken,paris).
byPlane(frankfurt,bangkok).
byPlane(frankfurt,singapore).
byPlane(paris,losAngeles).
byPlane(bangkok,auckland).
byPlane(singapore,auckland).
byPlane(losAngeles,auckland).
Write a predicate travel/2 which determines whether it is possible to
travel from one place to another by chaining together car, train, and
plane journeys. For example, your program should answer yes to the
query travel(valmont,raglan).
I solved this problem with the following code:
travel(From,To) :-
byCar(From,To).
travel(From,To) :-
byTrain(From,To).
travel(From,To) :-
byPlane(From,To).
travel(From,To) :-
byCar(From,NewTo),
travel(NewTo,To).
travel(From,To) :-
byTrain(From,NewTo),
travel(NewTo,To).
travel(From,To) :-
byPlane(From,NewTo),
travel(NewTo,To).
The follow-on problem is:
So, by using travel/2 to query the above database, you can find out
that it is possible to go from Valmont to Raglan. If you are planning
such a voyage, that’s already something useful to know, but you would
probably prefer to have the precise route from Valmont to Raglan.
Write a predicate travel/3 which tells you which route to take when
travelling from one place to another. For example, the program should
respond
X = go(valmont,metz,go(metz,paris,go(paris,losAngeles)))
to the query travel(valmont,losAngeles,X)
I have been struggling to populate X with a series of go(From,To) that show the successive steps of the journey. It looks like a recursive problem but I do not know how one should go about tackling it. This technique seems fundamental to Prolog programming, and I am quite interested in the thinking process to solve this problem and I look forward to any insight you can provide.
I had a go at this. I made one change to your first solution, just to remove some redundancy. I used the predicate connected/2 to generalize the relationship common to all connections appearing in the by_car/2, by_train/2, and by_plane/2 facts:
connected(From, To) :- by_car(From, To).
connected(From, To) :- by_train(From, To).
connected(From, To) :- by_plane(From, To).
Then I defined travel/2 as a recursive relationship over connected/2:
travel(From, To) :-
connected(From, To).
travel(From, To) :-
connected(From, Through),
travel(Through, To).
Turning to travel/3, notice that the final connection in the nested go... terms is a structure go/2, but the rest are go/3s. So we need to populate X with a series of nested go/3 structures that terminate in a go/2. This last is our base condition. Then it is simply a matter of repeating the second clause of travel/2, but including a go/3 in the third argument that will capture the values instantiated to From and Through on each iteration:
travel(From, To, go(From, To)) :-
connected(From, To).
travel(From, To, go(From, Through, Route)) :-
connected(From, Through),
travel(Through, To, Route).

Use Rule with in a Rule in Prolog

I need help. I am new in prolog and i haven't get used around with it. I wanted to get the remaining subjects with level 2 that joe did not get to enrolled to.
with these facts in prolog:
enrolled(joe,science).
enrolled(joe,math).
subjects(math, 2).
subject(science, 2).
subject(history,2).
subject(music, 2).
subject(health,3).
subject(literature,3).
My desired output is [history, music]. I made have this rule with combination of subtract and findall built in predicate but did not work. Can there be another possible solution for this? Thanks.
I don't know about subtract/2 (do you mean intersection ?).
Anyway, you should get the required list with findall/3:
get_subject_available(Name, X) :-
findall(S, (subject(S,2), \+enrolled(Name,S)), X).

Uses of non-ground facts in Prolog?

In Prolog you can write a ground fact as:
lost(jen).
You can also write a non-ground fact as:
lost(X).
Does this makes any sense? Could you show me a practical/real example where non ground facts are used?
Thanks,
Another case, avoiding lists, is where most cases are "true" and you just want to exclude some few cases that are false. So you deliberately fail thoses cases, then let everything else pass through.
Then you can do, say...
inhabited(antarctica) :- !, fail.
% all the other continents are inhabited
inhabited(_).
Well, you can have other things in facts besides atoms, for example you can have lists. Once you've done that, you may want to know about a one-element list, and you can have
oneelement([X]).
Likewise, say you want to compare what is the last element in a list
lastelement([X],X).
lastelement([_|Remainder],X) :- lastelement(Remainder,X).
The very useful member predicate is defined as
member([X|_],X).
member([_|Remainder],X) :- member(Remainder,X).
Each of these uses a non-ground fact as its base case, by matching a special form that's more specific than just lost(X)

Resources