Let's start with a good name! findgroups/2
that means you want to command Prolog: Prolog do find me some groups! And hurry up! Is this really fit? Let's see:
?- findgroups(L, [[1,2,3],[4,5,6],[7,8,9]]).
Who is finding here any group? They are already present! So your name is really a misnomer. Instead, compose a name by describing each argument. The first argument is about a list, the second about a list of lists. So:
?- list_lists(L, [[1,2,3],[4,5,6],[7,8,9]]).
Better, but a bit too general. Maybe:
?- elements_trigroups(L, [[1,2,3],[4,5,6],[7,8,9]]).
So the query now reads: Here are all the trigroups, what are the corresponding elements? Elements is such a lengthy word, els is just as nice.
My first (and a little bit too general) attempt:
es_trigroups(Es, Ess) :-
phrase(seqq(Ess), Es).
Note the variable names: Es
: a list of E
s. And Ess
is a list of Es
s which in turn is a list of E
s.
Using seqq//1
defined in another answer.
Darn, it still succeeds for:
?- es_trigroups([1,2,3,4,5], [Es,Fs]).
Es = [], Fs = [1,2,3,4,5]
; Es = [1], Fs = [2,3,4,5]
; ... .
But it is not that bad, for it succeeds for all the cases you demanded. Brief: The relation is too general. We need to specialize it.
A simple way to specialize a relation is to add further goals like:
es_trigroups(Es, Ess) :-
trigroups(Ess),
phrase(seqq(Ess), Es).
trigroups([]).
trigroups([Es|Ess]) :-
Es = [_,_,_|_],
trigroups(Ess).
So now everything seems fine. There is only one thing, that is not that nice: The termination property could be better. Sometimes we will need to exchange the goals.
es_trigroups_bis(Es, Ess) :-
phrase(seqq(Ess), Es),
trigroups(Ess).
The resulting termination conditions read:
es_trigroups(A,B)terminates_if b(B).
% optimal. loops found: [es_trigroups(_,[[_,_,_|_]|_]),es_trigroups(y,[[_,_,_|_]|_])]. NTI took 0ms,74i,74i
es_trigroups_bis(A,B)terminates_if b(B).
% optimal. loops found: [es_trigroups_bis(_,[[]|_]),es_trigroups_bis(y,[[]|_])]. NTI took 0ms,79i,79i
But what we actually want, is that the termination condition not only depends on B
(the second argument), but also on A
alone. That is that either A
or B
alone can guarantee termination. To this end, we have to interlace both definitions:
es_trigroups_ter(Es, Ess) :-
phrase(seq3s(Ess), Es).
seq3s([]) --> [].
seq3s([Es|Ess]) --> {Es = [_,_,_|_]}, seq(Es), seq3s(Ess).
Now, termination conditions are excellent!
es_trigroups_ter(A,B)terminates_if b(A);b(B).
% optimal. loops found: [es_trigroups_ter([A|_],[[A,_,_|_]|_])]. NTI took 0ms,77i,77i