List position in Prolog - prolog

I am trying to write a predicate that follows some simple conditions. It should take 2 lists and 2 variables and should return true if the first variable is located at the same position in the first list as the second variable is located in the second list. I did one part but I am struggling to get the other part working. This is what I have done so far, but in some way I need to check the rest of the positions in the list.
position([A|_],[B|_],Var1,Var2):-
A = Var1,
B = Var2.
I want for example to be able to write like this:
position([x,y,z],[1,2,3],z,3).
true .
Thanks in advance.
EDIT
I have tried and what I write keep giving me false, I thought this would work but it doesn't...:
position([A|C],[B|D],Var1,Var2):-
A = Var1,
B = Var2,
position(C,D,Var1,Var2).
Not sure why this doesn't work..

You need two clauses, one implementing the base case for when you find the variables in the same position and a clause implementing the recursive clause that you use to walk the list until either you found what you're looking for or reach the end of the lists. You're almost there:
position([Head1| _], [Head2| _], Var1, Var2) :-
Head1 == Var1,
Head2 == Var2.
position([_| Tail1], [_| Tail2], Var1, Var2) :-
position(Tail1, Tail2, Var1, Var2).
Note that you may need to use equality, (==)/2, as above instead of unification, (=)/2, as two variables always unify. But the choice depends on the possible inputs to your predicate and the exact desired semantics. Also, there can be several solutions. If you're interested in just one, you can add a cut to the end of the first clause or, in alternative, you can use a single clause with an if-then-else control construct:
position([Head1| Tail1], [Head2| Tail2], Var1, Var2) :-
( Head1 == Var1,
Head2 == Var2 ->
true
; position(Tail1, Tail2, Var1, Var2)
).

Related

Prolog, print employees with same names

This is my first time using Prolog.
I have employees:
employee(eID,firstname,lastname,month,year).
I have units:
unit(uID,type,eId).
I want to make a predicate
double_name(X).
that prints the last names of the employees with the same first name in the unit X.
I am doing something like this :
double_name(X) :-
unit(X,_,_eID),
employee(_eID,_firstname,_,_,_),
_name = _firstname,
employee(_,_name,_lastname,_,_),
write(_lastname).
But it prints all the employees in the unit.
How can i print only the employees with the same name ?
unit(unit_01,type,1).
unit(unit_01,type,2).
unit(unit_01,type,3).
employee(1,mary,smith,6,1992).
employee(2,fred,jones,1,1990).
employee(3,mary,cobbler,2,1995).
double_name(Unit) :-
unit(Unit,_,Eid_1),
employee(Eid_1,Firstname,Lastname_1,_,_),
unit(Unit,_,Eid_2),
Eid_1 \= Eid_2,
employee(Eid_2,Firstname,Lastname_2,_,_),
write(Firstname),write(","),write(Lastname_1),nl,
write(Firstname),write(","),write(Lastname_2).
Variables in Prolog typically start with an upper case letter, but starting them with and underscore is allowed, but not typical.
In double_name/2 the predicates like
unit(Unit,_,Eid_1)
employee(Eid_1,Firstname,Lastname_1,_,_)
are used to load the values from the facts into variables while pattern matching (via unification) that the bound variables match with the fact.
To ensure that a person is not compared with themselves.
Eid_1 \= Eid_2
and to make sure that two people have the same first name the same variable is used: Firstname.
The write/1 and nl/0 predicates just write the result to the screen.
Example:
?- double_name(unit_01).
mary,smith
mary,cobbler
true ;
mary,cobbler
mary,smith
true ;
false.
Notice that the correct answer is duplicated. This can be resolved.
See: Prolog check if first element in lists are not equal and second item in list is equal
and look at the use of normalize/4 and setof/3 in my answer
which I leave as an exercise for you.

Prolog dict predicate matching

Given this program, why am I forced to define every atom in the predicate, even if they're anonymous. Why is it that undefined variables in a dict predicate aren't thought of as anonymous?
funt2(X) :-
X = point{x:5, y:6}.
evalfunt(point{x:5, y : 6}) :-
write('hello world!').
evalfunt(point{x:_, y : _} ) :-
write('GoodBye world!').
Why can't I just say
evalfunt(point{x:5}) :-
write('GoodBye world!').
^that won't match, by the way.
I may as well just use a structure if I have to define every possible value in the dict to use dicts.
What's the motivation here? Can I do something to make my predicate terse? I'm trying to define a dict with 30 variables and this is a huge roadblock. It's going to increase my program size by a magnitude if I'm forced to define each variables (anonymous or not).
Dict is just a complex data type, like tuple, which has data AND structure. If you have, for example two facts:
fact(point{x:5, y:6}).
fact(point{x:5}).
Then the query
fact(point{x:_}).
will match the second one, but not the first one.
And the query
fact(point{x:_, y:_}).
Will match the first one, but not the second.
Now, if you want to match facts of the form fact(point{x:_, y:_, z:_}) only by one specific field, you can always write a helper rule:
matchByX(X, P) :- fact(P), P=point{x:X, y:_, z:_}.
So having facts:
fact(point{x:5, y:6, z:1}).
fact(point{x:1, y:2, z:3}).
fact(point{x:2, y:65, z:4}).
and quering
matchByX(1, P).
will return:
P = point{x:1, y:2, z:3}
UPDATE:
Moreover, in SWI-Prolog 7 version the field names can be matched as well, so it can be written in much more generic way, even for facts with different structures:
fact(point{x:5, y:6, z:1}).
fact(point{x:1, y:2}).
fact(point{x:2}).
fact(point{x:2, y:2}).
matchByField(F, X, P) :- fact(P), P.F = X.
So query:
?- matchByField(x, 2, P).
P = point{x:2} ;
P = point{x:2, y:2}.
I was able to accomplish what I needed by doing the following
checkiffive(Y) :-
get_dict(x, Y, V), V=5.
You need to use the built in methods for unifying values from a dict.
Described in chapter 5.4 of the SWI prolog reference
http://www.swi-prolog.org/download/devel/doc/SWI-Prolog-7.1.16.pdf

Asking for one of several conditions

I realize this is very basic, but I could not work this out from Prolog tutorials, so I hope someone here could help me solve my problem.
I have a term which is true if one of several conditions applies:
answer -->
Var,
a([Att1],[Var1]),
a([Att2],[Var2]),
a([Att3],[Var3]),
{
[one, two, three] = [Att1, Att2, Att3] -> Var1 = Var; % first condition
[one, three, two] = [Att1, Att2, Att3] -> Var1 = Var; % second condition
[two, one, three] = [Att1, Att2, Att3] -> Var2 = Var; % third condition
[three, one, two] = [Att1, Att2, Att3] -> Var2 = Var; % fourth condition
}
All Attributes and Variables come with a fixed value, and I want to offer "answer", if any of the conditions in the "{}" section are fulfilled - but for some reason, it doesn't work. The thing is, if I just check for one of the conditions, say, the first, it works as expected. But I don't want to copy/paste the rule 4 times because I didn't get a logical "or" to work properly.
Just to put it into words, in case I coded something completely different, the first condition is meant to say: check if Att1 is equal to one and Att2 is equal to two and Att3 is equal to three. If that is the case, also confirm that Var1 is equal to the value in Var. If not, check if any of the other conditions can be resolved.
edit: Turns out I just had a ';' too much in the code.

Getting specific data from Fact

I know that the Title ,does not mean anything , however , how to get 'calculas1' word and put it in list from this fact using prolog :
hasMark(calculas1 , 78 , 110).
In Prolog, you can query a fact this way:
hasMark(Subject, X, Y).
Which, in the case of your example, would yield:
Subject = calculus1
X = 78
Y = 110
The easiest way to collect them would be using the builtin, findall:
findall(Subject, hasMark(Subject, _, _), Subjects).
This will yield:
Subjects = [calculus1, ...]
The ... are other subjects, if you have them. Notice that I used _ for two of the parameters. That means I don't care what those values are. Any variable that starts with a _, including that character by itself, means "don't care".
You can also use a predicate like this:
add_subject( MyList, [Subject | MyList] ) :-
hasMark(Subject, _, _).
So you can query:
add_subject( [], List ).
And get:
List = [calculus1].
Note that a naming convention with underscores and lower case is more commonly used in Prolog than "camelCase". So it would be preferred to name your facts has_mark.

Pattern matching types in Prolog

Let's say I have a list looking like this:
List=[alpha(1,2),beta(3,4),gamma(4,1)]
Ok, so I want to make a certain pattern matching here... I know I can do:
Try=alpha(Y,Z).
Try=alpha(1,2)
Y=1
Z=2
But I would like to do for example:
Try=X(Y,Z)
X=alpha
Y=1
Z=2
...so that I can pass on the data to another predicate:
targetPredicate(Type,Value1,Value2):-
Type=alpha
...
and then do something with it instead of having to make one help predicate for every type I might run into:
helpPredicate(Input):-
Input=alpha(Value1, Value2),
targetPredicateAlt(Value1, Value2).
helpPredicate(Input):-
Input=beta(Value1, Value2),
targetPredicateAlt(Value1, Value2).
helpPredicate(Input):-
Input=gamma(Value1, Value2),
targetPredicateAlt(Value1, Value2).
Is there any way to get around this or am I doomed to use a ton of help predicates?
You can use the univ predicate =../2:
Suppose you have Try=alpha(1,2), then
Try =..[Name, X, Y].
would yield Name = alpha, X = 1, Y = 2.

Resources