Related
How would one implement a not_all_equal/1 predicate, which succeeds if the given list contains at least 2 different elements and fails otherwise?
Here is my attempt (a not very pure one):
not_all_equal(L) :-
( member(H1, L), member(H2, L), H1 \= H2 -> true
; list_to_set(L, S),
not_all_equal_(S)
).
not_all_equal_([H|T]) :-
( member(H1, T), dif(H, H1)
; not_all_equal_(T)
).
This however does not always have the best behaviour:
?- not_all_equal([A,B,C]), A = a, B = b.
A = a,
B = b ;
A = a,
B = b,
dif(a, C) ;
A = a,
B = b,
dif(b, C) ;
false.
In this example, only the first answer should come out, the two other ones are superfluous.
Here is a partial implementation using library(reif) for SICStus|SWI. It's certainly correct, as it produces an error when it is unable to proceed. But it lacks the generality we'd like to have.
not_all_equalp([A,B]) :-
dif(A,B).
not_all_equalp([A,B,C]) :-
if_(( dif(A,B) ; dif(A,C) ; dif(B,C) ), true, false ).
not_all_equalp([A,B,C,D]) :-
if_(( dif(A,B) ; dif(A,C) ; dif(A,D) ; dif(B,C) ; dif(B,D) ), true, false ).
not_all_equalp([_,_,_,_,_|_]) :-
throw(error(representation_error(reified_disjunction),'C\'est trop !')).
?- not_all_equalp(L).
L = [_A,_B], dif(_A,_B)
; L = [_A,_A,_B], dif(_A,_B)
; L = [_A,_B,_C], dif(_A,_B)
; L = [_A,_A,_A,_B], dif(_A,_B)
; L = [_A,_A,_B,_C], dif(_A,_B)
; L = [_A,_B,_C,_D], dif(_A,_B)
; error(representation_error(reified_disjunction),'C\'est trop !').
?- not_all_equalp([A,B,C]), A = a, B = b.
A = a, B = b
; false.
Edit: Now I realize that I do not need to add that many dif/2 goals at all! It suffices that one variable is different to the first one! No need for mutual exclusivity! I still feel a bit insecure to remove the dif(B,C) goals ...
not_all_equalp([A,B]) :-
dif(A,B).
not_all_equalp([A,B,C]) :-
if_(( dif(A,B) ; dif(A,C) ), true, false ).
not_all_equalp([A,B,C,D]) :-
if_(( dif(A,B) ; dif(A,C) ; dif(A,D) ), true, false ).
not_all_equalp([_,_,_,_,_|_]) :-
throw(error(representation_error(reified_disjunction),'C\'est trop !')).
The answers are exactly the same... what is happening here, me thinks. Is this version weaker, that is less consistent?
Here's a straightforward way you can do it and preserve logical-purity!
not_all_equal([E|Es]) :-
some_dif(Es, E).
some_dif([X|Xs], E) :-
( dif(X, E)
; X = E, some_dif(Xs, E)
).
Here are some sample queries using SWI-Prolog 7.7.2.
First, the most general query:
?- not_all_equal(Es).
dif(_A,_B), Es = [_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_A,_A,_B|_C]
...
Next, the query the OP gave in the question:
?- not_all_equal([A,B,C]), A=a, B=b.
A = a, B = b
; false. % <- the toplevel hints at non-determinism
Last, let's put the subgoal A=a, B=b upfront:
?- A=a, B=b, not_all_equal([A,B,C]).
A = a, B = b
; false. % <- (non-deterministic, like above)
Good, but ideally the last query should have succeeded deterministically!
Enter library(reif)
First argument indexing
takes the principal functor of the first predicate argument (plus a few simple built-in tests) into account to improve the determinism of sufficiently instantiated goals.
This, by itself, does not cover dif/2 satisfactorily.
What can we do? Work with
reified term equality/inequality—effectively indexing dif/2!
some_dif([X|Xs], E) :- % some_dif([X|Xs], E) :-
if_(dif(X,E), true, % ( dif(X,E), true
(X = E, some_dif(Xs,E)) % ; X = E, some_dif(Xs,E)
). % ).
Notice the similarities of the new and the old implementation!
Above, the goal X = E is redundant on the left-hand side. Let's remove it!
some_dif([X|Xs], E) :-
if_(dif(X,E), true, some_dif(Xs,E)).
Sweet! But, alas, we're not quite done (yet)!
?- not_all_equal(Xs).
DOES NOT TERMINATE
What's going on?
It turns out that the implementation of dif/3 prevents us from getting a nice answer sequence for the most general query. To do so—without using additional goals forcing fair enumeration—we need a tweaked implementation of dif/3, which I call diffirst/3:
diffirst(X, Y, T) :-
( X == Y -> T = false
; X \= Y -> T = true
; T = true, dif(X, Y)
; T = false, X = Y
).
Let's use diffirst/3 instead of dif/3 in the definition of predicate some_dif/2:
some_dif([X|Xs], E) :-
if_(diffirst(X,E), true, some_dif(Xs,E)).
So, at long last, here are above queries with the new some_dif/2:
?- not_all_equal(Es). % query #1
dif(_A,_B), Es = [_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_B|_C]
...
?- not_all_equal([A,B,C]), A=a, B=b. % query #2
A = a, B = b
; false.
?- A=a, B=b, not_all_equal([A,B,C]). % query #3
A = a, B = b.
Query #1 does not terminate, but has the same nice compact answer sequence. Good!
Query #2 is still non-determinstic. Okay. To me this is as good as it gets.
Query #3 has become deterministic: Better now!
The bottom line:
Use library(reif) to tame excess non-determinism while preserving logical purity!
diffirst/3 should find its way into library(reif) :)
EDIT: more general using a meta-predicate (suggested by a comment; thx!)
Let's generalize some_dif/2 like so:
:- meta_predicate some(2,?).
some(P_2, [X|Xs]) :-
if_(call(P_2,X), true, some(P_2,Xs)).
some/2 can be used with reified predicates other than diffirst/3.
Here an update to not_all_equal/1 which now uses some/2 instead of some_dif/2:
not_all_equal([X|Xs]) :-
some(diffirst(X), Xs).
Above sample queries still give the same answers, so I won't show these here.
I am having trouble generating all lists that meet certain criteria.
city(new_york, 47).
city(chicago, 100).
all_unique([]).
all_unique([H|T]) :- H = [] ; (not(member(H, T)), all_unique(T)).
cities([Head|Tail]) :-
length(Tail, L),
L < 2,
city(Head, _A),
(Tail = [] ; cities(Tail)).
When I issue the query cities(L), I want it to generate all lists of cities with a maximum length of 2 and no repetition. What it does now is return all possible lists and then keep trying lists that obviously don't meet the criteria.
?- cities(L).
L = [new_york] ;
L = [chicago] ;
L = [new_york, new_york] ;
L = [new_york, chicago] ;
L = [chicago, new_york] ;
L = [chicago, chicago] ;
ERROR: Out of global stack
?-
How do I tell Prolog not to try lists that are too long or have repeated items?
Your definition of all_unique/1 is better based on prolog-dif:
all_unique([]).
all_unique([E|Es]) :-
maplist(dif(E), Es),
all_unique(Es).
Based on meta-predicate maplist/2 you can define cities/1 like this:
city_(new_york, 47).
city_(chicago, 100).
city(C) :-
city_(C, _).
cities(List) :-
length(Ref, 2),
append(List, _, Ref),
all_unique(List),
maplist(city, List).
Sample query:
?- cities(Xs).
Xs = [] ;
Xs = [new_york] ;
Xs = [chicago] ;
Xs = [new_york, chicago] ;
Xs = [chicago, new_york] ;
false. % terminates universally
I'm new to Prolog and as an exercise I want to make an list invertion predicate. It uses the add_tail predicate that I made earlier—some parts might be redundant, but I don't care:
add_tail(A, [], A) :-
!.
add_tail([A|[]], H, [A,H]) :-
!.
add_tail([A|B], H, [A|C]) :-
add_tail(B,H,C).
It works same as builtin predicate append/3:
?- add_tail([a,b,c], d, A).
A = [a, b, c, d].
?- append([a,b,c], [d], A).
A = [a, b, c, d].
When I use append in my invert predicate, it works fine, but if I use add_tail, it fails:
invert([], []).
invert([A|B], C) :-
invert(B, D),
append(D, [A], C).
invert2([], []).
invert2([A|B], C) :-
invert2(B, D),
add_tail(D, A, C).
?- invert([a,b,c,d], A).
A = [d, c, b, a].
?- invert2([a,b,c,d], A).
false. % expected answer A = [d,c,b,a], like above
What exactly is my mistake? Thank you!
The implementation of add_tail/3 does not quite behave the way you expect it to.
Consider:
?- append([], [d], Xs).
Xs = [d].
?- add_tail([], d, Xs).
false.
That's bad... But it gets worse! There are even more issues with the code you presented:
By using (!)/0 you needlessly limit the versatility of your predicate.
Even though [A|[]] maybe correct, it obfuscates your code. Use [A] instead!
add_tail is a bad name for a predicate that works in more than one direction.
The variable names could be better, too! Why not use more descriptive names like As?
Look again at the variables you used in the last clause of add_tail/3!
add_tail([A|B], H, [A|C]) :-
add_tail(B, H, C).
Consider the improved variable names:
add_tail([A|As], E, [A|Xs]) :-
add_tail(As, E, Xs).
I suggest starting over like so:
list_item_appended([], X, [X]).
list_item_appended([E|Es], X, [E|Xs]) :-
list_item_appended(Es, X, Xs).
Let's put list_item_appended/3 to use in list_reverted/2!
list_reverted([], []).
list_reverted([E|Es], Xs) :-
list_reverted(Es, Fs),
list_item_appended(Fs, E, Xs).
Sample query:
?- list_reverted([a,b,c,d], Xs).
Xs = [d, c, b, a].
It is difficult to pinpoint your exact mistake, but the first two clauses of add_tail/3, the ones with the cuts, are wrong (unless I am misunderstanding what the predicate is supposed to do). Already the name is a bit misleading, and you should should care that you have redundant code.
list_back([], B, [B]).
list_back([X|Xs], B, [X|Ys]) :-
list_back(Xs, B, Ys).
This is a drop-in replacement for your add_tail/3 in your definition of invert/2. But as you are probably aware, this is not a very clever way of reversing a list. The textbook example of how to do it:
list_rev(L, R) :-
list_rev_1(L, [], R).
list_rev_1([], R, R).
list_rev_1([X|Xs], R0, R) :-
list_rev_1(Xs, [X|R0], R).
First try the most general query, to see which solutions exist in the most general case:
?- add_tail(X, Y, Z).
yielding the single answer:
X = Z,
Y = []
That's probably not the relation you intend to define here.
Hint: !/0 typically destroys all logical properties of your code, including the ability to use your predicates in all directions.
The first clause of add_tail/3 has a list as second argument, so it will never apply to your test case. Then we are left with 2 clauses (simplified)
add_tail([A],H,[A,H]):-!.
add_tail([A|B],H,[A|C]) :- add_tail(B,H,C).
You can see that we miss a matching clause for the empty list as first argument. Of course, append/3 instead has such match.
based on previous answer of "#mat" the problem is residue in the first two lines
your predicate add_tail is not like append because
with append i get this
| ?- append(X,Y,Z).
Z = Y,
X = [] ? ;
X = [_A],
Z = [_A|Y] ? ;
X = [_A,_B],
Z = [_A,_B|Y] ? ;
X = [_A,_B,_C],
Z = [_A,_B,_C|Y] ? ;
X = [_A,_B,_C,_D],
Z = [_A,_B,_C,_D|Y] ? ;
X = [_A,_B,_C,_D,_E],
Z = [_A,_B,_C,_D,_E|Y] ? ;y
and unfortunately with ur add_tail i get this result
| ?- add_tail(X,Y,Z).
Z = X,
Y = [] ? ;
X = [_A],
Z = [_A|Y] ? ;
X = [_A|_B],
Y = [],
Z = [_A|_B] ? ;
X = [_A,_B],
Z = [_A,_B|Y] ? ;
X = [_A,_B|_C],
Y = [],
Z = [_A,_B|_C] ?
X = [_A,_B,_C],
Z = [_A,_B,_C|Y] ? y
yes
after a simple modification in your add_tail code i obtained your expected result
code
% add_tail(A,[],A):-! . comment
add_tail([],H,H) :-!.
add_tail([A|B],H,[A|C]) :- add_tail(B,H,C).
test add_tail
| ?- add_tail(X,Y,Z).
Z = Y,
X = [] ? ;
X = [_A],
Z = [_A|Y] ? ;
X = [_A,_B],
Z = [_A,_B|Y] ? ;
X = [_A,_B,_C],
Z = [_A,_B,_C|Y] ? ;
X = [_A,_B,_C,_D],
Z = [_A,_B,_C,_D|Y] ? ;
X = [_A,_B,_C,_D,_E],
Z = [_A,_B,_C,_D,_E|Y] ? y
yes
finaly
i test ur invert predicate without modification
| ?- invert([_A,_B,_C],L).
L = [_C,_B,_A] ? ;
no
I hope this post help you to explain how the predicate done inside
enjoy
I have the following code:
born(person1,1991).
born(person2,1965).
born(person3,1966).
born(person4,1967).
born(person5,1968).
born(person6,1969).
criteria(X,Y):- born(X,Z) , born(Y,T) , Z<T.
order([]).
order([X]).
order([X,Y|L]) :- criteria(X,Y),order([Y|L]).
I have the predicate order([X,Y|L) that is true if the list is ordered , in this case, the first element should be the oldest person and the last element should be the youngest person.
My question is: how would you do a predicate print_List/1 that allows you to print the content of a list . An example of how it should work would be:
?-print_List([X]).
X = [person2, person3, person4, person5, person6, person1)
Your code it's a bit unusual, it builds a list 'lazily'...
?- order(X), write(X).
[]
X = [] ;
[_G357]
X = [_G357] ;
[person2,person1]
X = [person2, person1] ;
[person2,person3]
X = [person2, person3] ;
[person2,person3,person1]
X = [person2, person3, person1] ;
[person2,person3,person4]
X = [person2, person3, person4] .
....
and then a 'all solutions' built in is required, but findall/3 applied to it gives:
?- findall(X,order(X),L).
L = [[], [_G1108], [person2, person1], [person2, person3], [person2, person3, person1], [person2, person3, person4], [person2, person3|...], [person2|...], [...|...]|...].
You could consider to shorten the code using more directly any of the 'all solutions' built ins.
Anyway, when write or format don't fit, I use maplist. Paired with library(lambda) you get control in a fairly compact way: for instance, to display your data sorted:
?- setof(Y-P, Y^P^born(P, Y), L), maplist(writeln, L).
1965-person2
1966-person3
1967-person4
1968-person5
1969-person6
1991-person1
L = [1965-person2, 1966-person3, 1967-person4, 1968-person5, 1969-person6, 1991-person1].
Here setof/3 build a list sorted on Year, then with lambda we can recover the field of interest.
?- setof(Y-P, Y^P^born(P, Y), L), maplist(\E^(E=(Y-P), writeln(P)), L).
person2
person3
person4
person5
person6
person1
L = [1965-person2, 1966-person3, 1967-person4, 1968-person5, 1969-person6, 1991-person1].
Shouldn't write/1 do? Your example doesn't seem to show a print behavior, so you could simply call order with the right parameter (ordered born, either manually or create another predicate to generate it) and the Prolog system should show the content of X.
I try to create a list from the facts:
mother(jane,jerry).
mother(susan,riche).
mother(helen,kuyt).
I want to convert mothers' names to a list that has a number of elements in it like:
momlist([jane,susan],2).
momlist([jane,susan,helen],3).
momlist([jane],1).
I tried to create this with:
momlist(X,Number):- mom(X,_),
NewNum is Number-1,
NewNum > 0,
write(x),
momlist(X,NewNum).
It just write number times mom's names..
How can I produce a list with these fact?
Best regards and thanks a lot.
Here it is
mother(jane,jerry).
mother(susan,riche).
mother(helen,kuyt).
mother(govno,mocha).
mother(ponos,albinos).
momlist( X, L ) :-
length( X, L ),
gen_mum( X ),
is_set( X ).
gen_mum( [] ).
gen_mum( [X|Xs] ) :-
mother( X, _ ),
gen_mum( Xs ).
So
?- momlist(X, 3).
X = [jane, susan, helen] ;
X = [jane, susan, govno] ;
X = [jane, susan, ponos] ;
X = [jane, helen, susan] ;
X = [jane, helen, govno] ;
X = [jane, helen, ponos] ;
X = [jane, govno, susan] ;
And
?- momlist(X, 2).
X = [jane, susan] ;
X = [jane, helen] ;
X = [jane, govno] ;
X = [jane, ponos] ;
X = [susan, jane] ;
X = [susan, helen] ;
X = [susan, govno] ;
X = [susan, ponos] ;
X = [helen, jane] ;
Is that what you want?
A couple of minor problems with the accepted answer:
Adding a second child for a mother (e.g. mother(helen,todd).), will give duplicate results.
gen_mum produces a lot of results that are rejected because they are not a set (e.g. X = [jane, jane,jane]; X=[jane,jane,helen]].
Another possible solution would be:
momlist(X,L):-
setof(M, C^mother(M,C), AllMoms),
perm(L, AllMoms, X).
perm(0, _, []):- !.
perm(N, From, [H|T]):-
select(H, From, NewFrom),
NewN is N-1,
perm(NewN, NewFrom, T).
Also if you don't want [jane,helen] aswell as [helen,jane] etc. then you can use subset instead of perm:
subset(0,_,[]):- !.
subset(N, [M|TM], [M|T]):-
NewN is N-1,
subset(NewN, TM, T).
subset(N, [_|TM], L):-
subset(N, TM, L).