Related
I have an add2 predicate which resolves like this where s(0) is the successor of 0 i.e 1
?- add2(s(0)+s(s(0)), s(s(0)), Z).
Z = s(s(s(s(s(0)))))
?- add2(0, s(0)+s(s(0)), Z).
Z = s(s(s(0)))
?- add2(s(s(0)), s(0)+s(s(0)), Z).
Z = s(s(s(s(s(0)))))
etc..
I'm trying to do add in a predecessor predicate which will work like so
?- add2(p(s(0)), s(s(0)), Z).
Z = s(s(0))
?- add2(0, s(p(0)), Z).
Z = 0
?- add2(p(0)+s(s(0)),s(s(0)),Z).
Z = s(s(s(0)))
?- add2(p(0), p(0)+s(p(0)), Z).
Z = p(p(0))
I can't seem to find a way to do this. My code is below.
numeral(0).
numeral(s(X)) :- numeral(X).
numeral(X+Y) :- numeral(X), numeral(Y).
numeral(p(X)) :- numeral(X).
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
add(p(X),Y,p(Z)) :- add(X,Y,Z).
resolve(0,0).
resolve(s(X),s(Y)) :-
resolve(X,Y).
resolve(p(X),p(Y)) :-
resolve(X,Y).
resolve(X+Y,Z) :-
resolve(X,RX),
resolve(Y,RY),
add(RX,RY,Z).
add2(A,B,C) :-
resolve(A,RA),
resolve(B,RB),
add(RA,RB,C).
In general, adding with successor arithmetic means handling successor terms, which have the shape 0 or s(X) where X is also a successor term. This is addressed completely by this part of your code:
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
Now you have to make a decision; you can either handle the predecessors and the addition terms here, in add/3, or you can wrap this predicate in another one that will handle them. You appear to have chosen to wrap add/3 with add2/3. In that case, you will definitely need to create a reducing term, such as you've built here with resolve/2, and I agree with your implementation of part of it:
resolve(0,0).
resolve(s(X),s(Y)) :-
resolve(X,Y).
resolve(X+Y,Z) :-
resolve(X,RX),
resolve(Y,RY),
add(RX,RY,Z).
This is all good. What you're missing now is a way to handle p(X) terms. The right way to do this is to notice that you already have a way of deducting by one, by using add/3 with s(0):
resolve(p(X), R) :-
resolve(X, X1),
add(s(0), R, X1).
In other words, instead of computing X using X = Y - 1, we are computing X using X + 1 = Y.
Provided your inputs are never negative, your add2/3 predicate will now work.
predicate change_pos(E1, E2,Lin,Lout).
The Lin has any number of elements, and I need to change all occurences of E1 to E2, and vice-versa. And return in Lout.
I was thinking to do something like this:
change(X, Y, [], []).
change(X, Y, [X|L], [Y,L1]):- change(X,Y,L,L1).
change(X, Y, [Z|L], [Z,L1]:- X \== Z, change(X,Y,L,L1).
But this way is not swiping two number of the list
I'm supposing, since this is homework, it's an exercise to learn list processing and recursion. But in Prolog, a common tool for processing each term in turn in a list is maplist:
% Rule for changing one element
change_element(X, Y, X, Y).
change_element(X, Y, Y, X).
change_element(X, Y, Z, Z) :- dif(X, Z), dif(Y, Z).
% Rule for changing a list
change(X, Y, L1, L2) :-
maplist(change_element(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b] ? ;
no
?-
For a determinate solution, you can use if_/3:
change1(X, Y, A, B) :-
if_(=(Y, A), B = X, A = B).
change2(X, Y, A, B) :-
if_(=(X, A), B = Y, change1(X, Y, A, B)).
change(X, Y, L1, L2) :- maplist(change2(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b].
?-
You're almost there. Your base case (the empty lists) and your second rule (swap X for Y) are basically fine (apart from the details pointed out in the comments). However, you are missing a rule for vice-versa (swap Y for X). And in your last rule you likely want to make sure that Z differs not only from X but also from Y, otherwise Z would be subject to rule two or three.
change(X, Y, [], []).
change(X, Y, [X|L], [Y|L1]) :-
change(X,Y,L,L1).
change(X, Y, [Y|L], [X|L1]) :- % <- vice versa case
change(X,Y,L,L1).
change(X, Y, [Z|L], [Z|L1]) :-
dif(X,Z), % <- neither X=Z
dif(Y,Z), % <- nor vice versa
change(X,Y,L,L1).
Here are some example queries. What does [1,2,3,4] look like after swapping 1 with 2 and vice versa?
?- change(1,2,[1,2,3,4],L).
L = [2,1,3,4] ? ;
no
What did [2,1,3,4] look like before swapping 1 with 2 and vice versa?
?- change(1,2,L,[2,1,3,4]).
L = [1,2,3,4] ? ;
no
Which elements have been swapped in [1,2,3,4] if the resulting list is [2,1,3,4] ?
?- change(X,Y,[1,2,3,4],[2,1,3,4]).
X = 1,
Y = 2 ? ;
X = 2,
Y = 1 ? ;
no
I have this Prolog code that returns: [[vincent,vincent],[vincent,marcellus],[marcellus,vincent],[marcellus,marcellus],[pumpkin,pumpkin],[honey_bunny,honey_bunny]].
:- initialization main.
loves(vincent, mia).
loves(marcellus, mia).
loves(pumpkin, honey_bunny).
loves(honey_bunny, pumpkin).
jealous(X, Y) :-
loves(X, Z),
loves(Y, Z).
main :-
findall([X, Y], jealous(X, Y), L),
write(L),
halt.
How to get the only results when X != Y?
I tried the following code to get the same results as before.
jealous(X, Y) :-
X \== Y,
loves(X, Z),
loves(Y, Z).
With \=, I got [].
How to get only [vincent,marcellus] as a result?
The order of the goals in your attempted solution is wrong. When called with two distinct variables, the (\==)/2 standard predicate always succeed. The solution is to call the predicate only when its arguments are instantiated:
jealous(X, Y) :-
loves(X, Z),
loves(Y, Z),
X \== Y.
With this fix, your query now returns:
?- findall([X, Y], jealous(X, Y), L).
L = [[vincent, marcellus], [marcellus, vincent]].
So, no one is jealous of himself anymore. But you still get a redundant solution. We can modify the jealous/2 predicate to sort the names in the returned solutions. For example:
jealous(X, Y) :-
loves(X0, Z),
loves(Y0, Z),
X0 \== Y0,
( X0 #< Y0 ->
X = X0, Y = Y0
; X = Y0, Y = X0
).
Now, by using setof/3 instead of findall/3, we get:
?- setof([X, Y], jealous(X, Y), L).
L = [[marcellus, vincent]].
One final observation. A list is a poor solution for representing a pair. The traditional way is to use either X-Y or (X, Y).
Whenever possible, use dif/2 instead of (\==)/2.
dif/2 will help you write logically sound programs.
For details, look at prolog-dif!
Suppose you have a database with the following content:
son(a, d).
son(b, d).
son(a, c).
son(b, c).
So a and b are sons of d and c. Now you want to know, given a bigger database, who is brother to who. A solution would be:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y.
The problem with this is that if you ask "brother(X, Y)." and start pressing ";" you'll get redundant results like:
X = a, Y = b;
X = b, Y = a;
X = a, Y = b;
X = b, Y = a;
I can understand why I get these results but I am looking for a way to fix this. What can I do?
Prolog will always try to find every possible solution available for your statements considering your set of truths. The expansion works as depth-first search:
son(a, d).
son(b, d).
son(a, c).
son(b, c).
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y.
brother(X, Y)
_______________________|____________________________ [son(X, P)]
| | | |
X = a, P = d X = b, P = d X = a, P = c X = a, P = b
| | | |
| ... ... ...
|
| (X and P are already defined for this branch;
| the algorithm now looks for Y's)
|__________________________________________ [son(Y, d)]
| |
son(a, d) -> Y = a son(b, d) -> Y = b
| |
| | [X \= Y]
X = a, Y = a -> false X = a, Y = b -> true
|
|
solution(X = a, Y = b, P = d)
But, as you can see, the expansion will be performed in all the branches, so you'll end up with more of the same solution as the final answer. As pointed by #Daniel Lyons, you may use the setof built-in.
You may also use the ! -- cut operator -- that stops the "horizontal" expansion, once a branch has been found to be valid, or add some statement that avoids the multiple solutions.
For further information, take a look at the Unification algorithm.
First, I would advise against updating the Prolog database dynamically. For some reasons, consider the article
"How to deal with the Prolog dynamic database?".
You could use a combination of the builtin setof/3 and member/2, as #DanielLyons has suggested in his answer.
As yet another alternative, consider the following query which uses setof/3 in a rather unusual way, like this:
?- setof(t,brother(X,Y),_).
X = a, Y = b ;
X = b, Y = a.
You can eliminate one set with a comparison:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y, X #< Y.
?- brother(X, Y).
X = a,
Y = b ;
X = a,
Y = b ;
false.
Since X and Y will be instantiated both ways, requiring X be less than Y is a good way to cut the solutions in half.
Your second problem is that X and Y are brothers by more than one parent. The easiest solution here would be to make your rules more explicit:
mother(a, d).
mother(b, d).
father(a, c).
father(b, c).
brother(X, Y) :-
mother(X, M), mother(Y, M),
father(X, F), father(Y, F),
X \= Y, X #< Y.
?- brother(X, Y).
X = a,
Y = b ;
false.
This method is very specific to this particular problem, but the underlying reasoning is not: you had two copies because a and b are "brothers" by c and also by d—Prolog was right to produce that solution twice because there was a hidden variable being instantiated to two different values.
A more elegant solution would probably be to use setof/3 to get the solutions. This can work even with your original code:
?- setof(X-Y, (brother(X, Y), X #< Y), Brothers).
Brothers = [a-b].
The downside to this approach is that you wind up with a list rather than Prolog generating different solutions, though you can recover that behavior with member/2.
This should work. But I think it can be improved (I am not a Prolog specialist):
brother(X, Y) :-
son(X, P1),
son(Y, P1),
X #< Y,
(son(X, P2), son(Y, P2), P1 #< P2 -> false; true).
If you're using Strawberry Prolog compiler,you won't get all the answers by typing this:
?- brother(X, Y),
write(X), nl,
write(Y), nl.
In order to get all the answers write this:
?- brother(X, Y),
write(X), nl,
write(Y), nl,
fail.
I hope it helps you.:)
I got to an answer.
% Include the dictionary
:- [p1]. % The dictionary with sons
:- dynamic(found/2).
brother(X, Y) :-
% Get two persons from the database to test
son(X, P),
son(Y, P),
% Test if the two persons are different and were not already used
testBrother(X, Y).
% If it got here it's because there is no one else to test above, so just fail and retract all
brother(_, _) :-
retract(found(_, _)),
fail.
testBrother(X, Y) :-
X \= Y,
\+found(X, Y),
\+found(Y, X),
% If they were not used succed and assert what was found
assert(found(X, Y)).
It always returns fails in the end but it succeeds with the following.
brother(X, Y). % Every brother without repetition
brother('Urraca', X). % Every brother of Urraca without repetition
brother('Urraca', 'Sancho I'). % True, because Urraca and Sancho I have the same father and mother. In fact, even if they only had the same mother or the same father it would return true. A little off context but still valid, if they have three or more common parents it would still work
It fails with the following:
brother(X, X). % False because it's the same person
brother('Nope', X). % False because not is not even in the database
brother('Nope', 'Sancho I'). % False, same reason
So like this I can, for example, ask: brother(X, Y), and start pressing ";" to see every brother and sister without any repetition.
I can also do brother(a, b) and brother(b, a), assuming a and b are persons in the database. This is important because some solutions would use #< to test things and like so brother(b, a) would fail.
So there it is.
What I want to do is to delete part of a list specified in another list i.e. e.g.
?- deleteSome([1,4,3,3,2,2],[1,2,4],Z).
Z = [3,3,2].
I first defined the following. No problem there.
deleteOne(X, [X|Z], Z).
deleteOne(X, [V|Z], [V|Y]) :-
X \== V,
deleteOne(X,Z,Y).
Then, the following does not work as expected.
deleteSome([], [], _).
deleteSome([X|Xs], Y, Zs) :-
deleteSome(Xs, Y, [X|Zs]).
deleteSome([X|Xs], Y, Zs) :-
member(X,Y),
deleteOne(X,Y,Y),
deleteSome(Xs, Y, Zs).
I would use the powerful select/3 builtin
deleteSome(L, D, R) :-
select(E, L, L1),
select(E, D, D1),
!, deleteSome(L1, D1, R).
deleteSome(L, _, L).
test:
?- deleteSome([1,4,3,3,2,2],[1,2,4],Z).
Z = [3, 3, 2].
I must admit, I don't understand your deleteSome code at all. Here's what I'd do (no Prolog here, so might contain errors):
deleteSome(X, [], X).
deleteSome(X, [Y|Ys], Z) :-
deleteOne(Y, X, T),
deleteSome(T, Ys, Z).
I.e. If there's nothing to delete, no change. Otherwise, the result is when we delete the first of the to-deletes, and then delete the rest of them.
There is some confusion in that it seems your deleteOne has (Original, ToDelete, Result) parameters, but deleteSome has (ToDelete, Original, Result). For consistency, I'd rather rewrite it so the signatures are compatible:
deleteSome([], Y, Y).
deleteSome([X|Xs], Y, Z) :-
deleteOne(X, Y, T),
deleteSome(Xs, T, Z).