I am new to prolog and I am trying to create a predicate and am having some trouble.
I have a list of cities that are connected via train. They are connected via my links/2 clause.
links(toronto, ajax).
links(toronto, markham).
links(toronto, brampton).
links(brampton, markham).
links(markham, ajax).
links(brampton, mississauga).
links(mississauga, toronto).
links(mississuaga, oakville).
links(oakville, st.catharines).
links(oakville, hamilton).
links(hamilton, st.catharines).
I am writing a predicate called addnewcities which will take a list of cities and then return a new list containing the original list, plus all the cities that are directly connected to each of the cities in the original list.
Here is a (rough looking) visual representation of the links.
If my input list was [toronto] I want my output to be (order doesnt matter) [ajax,markham,brampton,mississauga,toronto].
If input was [oakville,hamilton] I want the output to be [mississauga,st.catharines,oakville,hamilton].
Here is my predicate so far.
addnewcities([],_).
addnewcities([CitiesH|Tail],Ans):- directer(CitiesH,Ans2), merger(Ans2,[CitiesH],Ans), addnewcities(Tail,Ans).
directer/2 takes a city and saves a list containing all the directly connected cities in the second arg.
merger/3 just merges two lists making sure there are no duplicates in the final list.
When my input is a list with one element ie [toronto] it works!
But when I have a list with multiple elements [toronto,ajax] it says "false" every time.
I'm pretty sure my issue is that when it recurses for the second time, merge is what says its false. I just don't know how to get around this so that my list can keep being updated instead of being checked if true or false.
Any help is appreciated!
this query uses library support to solve the problem:
addcities(Cs, L) :-
setof(D, C^(member(C,Cs), (C=D;link(C,D);link(D,C))), L).
This should work for what you want:
addcities(A,B):-
addcitiesaux(A,[],B).
addcitiesaux([],X,X).
addcitiesaux([X|Xs],L,R):-
link(X,A),
\+ member(A,L),
!,
addcitiesaux([X|Xs],[A|L],R).
addcitiesaux([X|Xs],L,R):-
link(A,X),
\+ member(A,L),
!,
addcitiesaux([X|Xs],[A|L],R).
addcitiesaux([X|Xs],L,R):-
addcitiesaux(Xs,[X|L],R).
Related
I have a term contained in a file:
fruit(apple, []).
I'm trying to write input to it, so that each set of information will be appending to the empty list as a list to compose a list of lists, in a manner like:
fruit(apple, [[30, 'fresh'], [10, 'old'], ... ]).
So far I only know how to write a separate term:
add_fruit(File, Type, Price, State) :-
open(File, append, Stream),
writeq(Stream, fruit(Type, [Price, State])),
write(Stream, '.'),
nl(Stream), nl(Stream),
close(Stream).
This will produce a term such as:
fruit(apple, [20, 'some state']).
However I don't want to have to create a new term every time I use the add_fruit predicate, rather I want to append a list containing Price and State to the appropriate fruit type term.
Would it be possible to extend the predicate so that it will write to the existing term, rather than create a new one?
You are mixing up concepts here a bit. First off, if you have a Prolog file, say "food.pl" with the contents:
fruit(apple, []).
then fruit/2 is not exactly a term, but rather the fact fruit/2 (predicate without a body, only with a head) which maps the atom apple (first argument) to the empty list (the second argument).
What you can do now is consult the file, which will put the fact in the database.
Another thing: are you sure you need to keep appending to the list in the second argument? Why not normalize your database, and have, for example:
fruit(apple, price_state(30, fresh)).
fruit(apple, price_state(10, old)).
% etc
Here, you now have a table, fruit, with two columns. The first is the name of the fruit, the second is a term price_state/2 with the price as the first argument and the state as the second. You could have just as well said:
fruit_price_state(apple, 30, fresh).
fruit_price_state(apple, 10, old).
% etc
if you indeed want your table to map the fruit to a state and a price. You can now add and remove rows from the table using assertz and retract. In other words, design your database as you would design a relational database, using facts as tables. This approach translates directly to Prolog. You can then query the database, for example, to give you the combination of price and state for apples:
?- bagof(price_state(P, S), fruit(apple, P, S), PSs).
This will put a list of price_state/2 in PSs, or fail, if you don't have apples in your database (you could use findall/3 if you prefer to get an empty list instead, but then you would have to deal with that empty list in any predicate that takes PSs).
One way to deal with persistence, that is, load facts to the database, add/remove rows, and then save the updated database back to the same file is using Edinburgh-style I/O with see, tell, told etc.
If you are using SWI-Prolog, you also have the option of using library(persistency). See the link for a working minimal example.
So I've been trying to implement this function in my module and so far I got this:
EXAMPLE 1.
[2,[3,[4,[5,[6,[7,[8,[]]]]]]]]
I am trying to figure out how I can make it look like a proper list, ie:
EXAMPLE 2.
[2,3,4,5,6,7,8].
I know I have to play with Heads and Tails but I am miserably failing at understanding it.
Any help would be appreciated.
Thanks!
Actually in the example 1 you show proper list. List that just consists of 2 elements - number and another list.
Improper list is different thing - for instance [1|2].
You can turn example 1 into example 2 by lists:flatten.
1> M = [2,[3,[4,[5,[6,[7,[8,[]]]]]]]].
[2,[3,[4,[5,[6,[7,[8,[]]]]]]]]
2> lists:flatten(M).
[2,3,4,5,6,7,8]
The root of the problem is how you have built your list. What you have here:
[2,[3,[4,[5,[6,[7,[8,[]]]]]]]]
is not one list but nested lists each of two elements. When you do [Element,List] this does NOT prepend Element to List but builds a new list with Element as the first element and List as the second element. Note that each list is a proper list but you have not built one list but nested lists.
To prepend Element to List you use the syntax [Element | List]. So:
[2|[3|[4|[5|[6|[7|[8|[]]]]]]]]
which builds the list [1,2,3,4,5,6,7,8].
So [Element | List] and [Element,List] are two very different things, the first prepends an element to the beginning of a list while the second builds a new list of two elements. There is no direct way of appending an element to a list without rebuilding the list.
Not as obvious as it looks at first, but this is a manual way of doing what lists:flatten/1 does (in this particular case, its more interesting otherwise):
proper(L) -> proper([], L).
proper(A, [H|[T]]) -> proper([H|A], T);
proper(A, []) -> lists:reverse(A).
I have a list in prolog that contains several items. I need to 'normalized' the content of this list and write the result to a new list. But I still have problem in doing it.
The following code shows how I did it:
normalizeLists(SourceList, DestList) :-
% get all the member of the source list, one by one
member(Item, SourceList),
% normalize the item
normalizeItem(Item, NormItem),
% add the normalize Item to the Destination List (it was set [] at beginning)
append(NormItem, DestList, DestList).
The problem is in the append predicate. I guess it is because in prolog, I cannot do something like in imperative programming, such as:
DestList = DestList + NormItem,
But how can I do something like that in Prolog? Or if my approach is incorrect, how can I write prolog code to solve this kind of problem.
Any help is really appreciated.
Cheers
Variables in Prolog cannot be modified, once bound by unification. That is a variable is either free or has a definite value (a term, could be another variable). Then append(NormItem, DestList, DestList) will fail for any NormItem that it's not an empty list.
Another problem it's that NormItem it's not a list at all. You can try
normalizeLists([], []).
normalizeLists([Item|Rest], [NormItem|NormRest]) :-
% normalize the item
normalizeItem(Item, NormItem),
normalizeLists(Rest, NormRest).
or (if your Prolog support it) skip altogether such definition, and use an higher order predicate, like maplist
...
maplist(normalizeItem, Items, Normalized),
...
I am having trouble with recursive searching of list and creation of list of lists from the result..
The knowledge base contains team name, number of wins and zone they are in, all associated withe their team number. I am passing list of team numbers in Teams and I am searching for a matching pair with findMinMax/3. The result I need is...
List of lists of paired teams (ex. X = [[gonzaga, washington], [iowa, oklahoma], …])
And 1 unmatched team (resulted from odd number of teams) or 0 (in case of even)
I figured out everything else and can get up to the part [gonzaga, washington], but failing at recursive portion...
findPair(Teams,[HL|TL],Rest) :-
findMinMax(Teams,Min,Max),
delete(Teams,Min,TeamsNoMin),
delete(TeamsNoMin,Max,Rest),
createPair(Min,Max,Pair), %Pair = "["Min_team","Max_team"]"
append(HL,[Pair],TL),
findPair(Rest,TL,[]).
A general recursive scheme
Here I'll try to show you how we usually perform recursion in Prolog. It's not simple to get for beginners because the lists are built "backwards": nothing gets really built until we hit the end of the list.
The reason for this "build backwards" principle is that once a variable is set, you can't set it to another value, so for example it'd be hard to say that the result is [1] at the first step of the recursion and then becomes [1, 2]. Instead, what we say in Prolog is that the result head is 1 and that the result tail is the result of the recursive call (yeah read it twice if it got messy : d). So as long as we do not hit a base case (a case where no recursion is performed), we don't bind variables definitely (ie we always let a part of the term unbound).
For a predicate rec/2: rec(Input, Result) producing a result list from an input list by linking their elements with somepredicate/2, we'd write:
rec([InputHead|InputTail], [ResultHead|ResultTail]) :-
somepredicate(InputHead, ResultHead),
rec(InputTail, ResultTail).
to represent that.
Here you can see that we stated that the head of the result is ResultHead and that its tail is calculated thanks to the call rec(InputTail, ResultTail).
Now that's fine but we need to stop at some point, when the list is empty, for example. We'd write that as follows:
rec([], []).
which means: when the input list is empty, so is the result list.
An application to your predicate
Now, to fix your problem, you first have to fix the recursive clause:
findPair(Teams,[HL|TL],Rest) :-
findMinMax(Teams,Min,Max),
delete(Teams,Min,TeamsNoMin),
delete(TeamsNoMin,Max,Rest),
createPair(Min,Max,Pair), %Pair = "["Min_team","Max_team"]"
append(HL,[Pair],TL),
findPair(Rest,TL,[]).
would become
findPair(Teams, [Pair|Tail], LeftOver) :-
findMinMax(Teams, Min, Max),
delete(Teams, Min, TeamsNoMin),
delete(TeamsNoMin, Max, Rest),
createPair(Min, Max, Pair), %Pair = "["Min_team","Max_team"]"
findPair(Rest, Tail, LeftOver).
Important to note: now Rest has become two separate variables. The last argument of findPair/3 doesn't get changed anymore, since in the recursive call we do not know anything about it yet, so we can't bind it, and the in-predicate Rest is therefore now independant and just represents the teams that have not been handled yet and are therefore of interest for the tail of our result list (and for LeftOver).
Now we have to handle the base cases:
when there are no teams left
findPair([], [], []).
Here we say that when Teams is empty, so are the Result and LeftOver.
when there is one team left
findPair([Last], [], [Last]).
Here we say that when Teams has only one element, LeftOver is equal to Teams and Result is empty.
Resulting code is:
findPair([], [], []).
findPair([Last], [], [Last]).
findPair(Teams, [Pair|Tail], LeftOver) :-
findMinMax(Teams, Min, Max),
delete(Teams, Min, TeamsNoMin),
delete(TeamsNoMin, Max, Rest),
createPair(Min, Max, Pair), %Pair = "["Min_team","Max_team"]"
findPair(Rest, Tail, LeftOver).
To make your clauses exclusive you could replace Teams with [Not, Empty|AtAll] to ensure the last clause is used only with lists of length 2 or more, or just add a guard such as Teams = [_, _|_], at the start of the clause.
Hope it helped and do not hesitate to ask for clarifications in comments :)
I have three types of facts:
album(code, artist, title, date).
songs(code, songlist).
musicians(code, list).
Example:
album(123, 'Rolling Stones', 'Beggars Banquet', 1968).
songs(123, ['Sympathy for the Devil', 'Street Fighting Man']).
musicians(123, [[vocals, 'Mick Jagger'], [guitar, 'Keith Richards', 'Brian Jones']].
I need to create these 4 rules:
together(X,Y) This succeeds if X and Y have played on the same album.
artistchain(X,Y) This succeeds if a chain of albums exists from X to Y;
two musicians are linked in the chain by 'together'.
role(X,Y) This succeeds if X had role Y (e.g. guitar) ever.
song(X,Y) This succeeds if artist X recorded song Y.
Any help?
I haven't been able to come up with much but for role(X,Y) I came up with:
role(X,Y) :- prole(X,Y,musicians(_,W)).
prole(X,Y,[[Y|[X|T]]|Z]).
prole(X,Y,[[Y|[H|T]]|Z]) :- prole(X,Y,[[Y|T]|Z]).
prole(X,Y,[A|Z]) :- prole(X,Y,Z).
But that doesn't work. It does work if I manually put in a list instead of musicians(_,W) like [[1,2,3],[4,5,6]].
Is there another way for me to insert the list as a variable?
As for the other rules I'm at a complete loss. Any help would really be appreciated.
You have a misconception about Prolog: Answering a goal in Prolog is not the same as calling a function!
E.g.: You expect that when "role(X,Y) :- prole(X,Y,musicians(_,W))." is executed, "musicians(_,W)" will be evaluated, because it is an argument to "prole". This is not how Prolog works. At each step, it attempts to unify the goal with a stored predicate, and all arguments are treaded either as variables or grounded terms.
The correct way to do it is:
role(X,Y) :- musicians(_, L), prole(X,Y,L).
The first goal unifies L with a list of musicians, and the second goal finds the role (assuming that the rest of your code is correct).
Little Bobby Tables is right, you need to understand the declarative style of Prolog. Your aim is to provide a set of rules that will match against the set of facts in the database.
Very simply, imagine that I have the following database
guitarist(keith).
guitarist(jim).
in_band('Rolling Stones', keith).
in_band('Rolling Stones', mick).
Supposed I want to find out who is both a guitarist and in the Rolling Stones. I could use a rule like this
stones_guitarist(X):-
guitarist(X),
in_band('Rolling Stones', X).
When a variable name is given within a rule (in this case X) it holds its value during the rule, so what we're saying is that the X which is a guitarist must also be the same X that is in a band called 'Rolling Stones'.
There are lots of possible ways for you to arrange the database. For example it might be easier if the names of the musicians were themselves a list (e.g. [guitar,[keith,brian]]).
I hope the following example for song(X,Y) is of some help. I'm using Sicstus Prolog so import the lists library to get 'member', but if you don't have that it's fairly easy to make it yourself.
:- use_module(library(lists)).
song(ARTIST,SONG):-
album(CODE,ARTIST,_,_),
songs(CODE,TRACKS),
member(SONG,TRACKS).