backward forward
backward forward

Reputation: 467

How to read from a list in GNU prolog?

So I have an assignment where I am to produce compatible meeting times between 3 different people. In the prolog file where I define predicates, there is a line given that has the name of the three people I am supposed to compare that reads as follows:

people([ann,bob,carla]).

Where we are supposed to match these names from a data file that defines facts, where a fact holds the following format:

free(ann,slot(time(7,0,am),time(9,0,am))).

My question is, how do I read through 'people' so that I can match names against each other?

My text book doesn't really explain prolog too well, and I am confused on what 'people' actually is (when I say what it actually is, I mean is 'people' a list? an array?) so I am having troubles even searching for a solution as to how to read through each name so I can compare them.

Upvotes: 1

Views: 549

Answers (1)

Duda
Duda

Reputation: 3736

people([ann,bob,carla]). is a fact. The predicate people/1 holds a list of people names. In prolog you have different ways to get elements from a list.

The most "dirtiest" version is just to write the list with a fixed number of elements:

?- people([P1,P2,P3]).
P1 = ann,
P2 = bob,
P3 = carla ;
false.

You should not do this, because it works only for sets of 3 people and you would have to alter your code everytime a person leaves/enters.

Normally you go through a prolog list where you just get the first element Head and the rest of a list Tail:

?- people([Head|Tail]).
Head = ann,
Tail = [bob, carla] ;
false.

By redoing this you can traverse through the whole list until the list has only one element left. To do this you need a help predicate, which I named person. person takes as first element a List and as second a variable (or a name for test). It unificates the variable with one element from the list:

person([H|_], H).
person([_|T], P):-
    person(T, P).

?- people(L), person(L,P).

L = [ann, bob, carla],
P = ann ;

L = [ann, bob, carla],
P = bob ;

L = [ann, bob, carla],
P = carla ;

false.

It works as follows: you have a list and imagine you see the first element from it only. You have two choices here: first you are ok with just taking the head element as an output, so the second attribute should be the exact same as the head element: person([H|_], H).
Or second: you ignore the head element and try to find something in the rest of the list by just calling the predicate again with a smaller list: person([_|T], P):- person(T, P).
When a variable starts with an underscore _ you are not interested in its content.

Also worth knowing: there are (most likely) inbuild helper predicates such as member/2 which give you back any member of a list:

?- people(L), member(P,L).

will give you any person in L.

To access a single timeslot for a choosen person you simply ask for the predicate free with your person from the list:

?- people(L), member(P,L), free(P,S).

If you want to find a timeslot where all persons in the list have to participate you need to define a helper predicate. I named it hastime

hastime([],_).
hastime([H|L], S):-
    free(H,S),
    hastime(L,S).

The output of ?- people(L), free(_,S), hastime(L,S). will give you a timeslot S where everone has time. Before calling hastime/2 you guess a Timeslot S. hastime/2 will look if all of the people have time on S: if there are no people (empty list []) you can accept any timeslot (_). If there are at least one person H in your list: ask if H has time on timeslot S and try if the other people from the list have this timeslot S free as well by calling the predicate for the tail list.
If prolog choose a slot where not all of them have time, it will go back to the point where it choosed the timeslot S and will look for a different value and try again. If there are no such timeslots it will return false.
Also hastime/2 can be used to find a timeslot by itself, but using it as a "generator" and test at the same time is a bit confusing.

Upvotes: 5

Related Questions