Using seq//1
:
list_splitonstop(Xs, As, Bs) :-
phrase( ( seq(As), [stop], seq(Bs) ), Xs).
This version works as you expected:
?- L = [tea,coffee,sugar,cake,stop,meat,fish,eggs,flour],
list_splitonstop(L, L1, L2).
L = [tea,coffee,sugar,cake,stop,meat,fish,eggs,flour],
L1 = [tea,coffee,sugar,cake], L2 = [meat,fish,eggs,flour]
; false.
But, is it really the best solution? This ; false
at the end may be an indication that it is not. But we cannot say this for sure. We would have to figure out another case where this solution does not work as expected. You are faced with similar problems also in other programming languages were one has to rely a lot on the imagination of the programmer to find out border cases and the like.
Fortunately, we are here using Prolog which helps us to understand what we are actually defining.
A very simple first start is to ask the most general query. Just like that:
?- list_splitonstop(L, L1, L2).
L = [stop], L1 = [], L2 = []
; L = [stop,_A], L1 = [], L2 = [_A]
; L = [stop,_A,_B], L1 = [], L2 = [_A,_B]
; L = [stop,_A,_B,_C], L1 = [], L2 = [_A,_B,_C]
; ... .
Look at each answer! Let's take the third as an example. L = [stop,_A,_B]
means that this answer includes all lists with three elements where the first is stop
. So we are looking here at an infinity of solutions that have been all compactly described with a couple of characters! Not even bzip2 -99
can do that!
Are these the only lists with three elements? We cannot say this from this single query alone, for Prolog might enumerate answers in an unfair manner. Imagine you ask someone to tell you all the natural numbers, but that person starts 0, 2, 4, ... Evidently, that enumeration is very unfair to the odd numbers. Similarly some answers might be missing ...
In Prolog we can insist on looking at lists of length 3 only:
?- L = [_,_,_], list_splitonstop(L, L1, L2).
L = [stop,_A,_B], L1 = [], L2 = [_A,_B]
; L = [_A,stop,_B], L1 = [_A], L2 = [_B]
; L = [_A,_B,stop], L1 = [_A,_B], L2 = []
; false.
So we can ask for all relevant cases of length 3 in a single query. Note that these _A
and _B
variables represent any term! Please take a moment and appreciate what you are looking at: All cases for lists of length 3. There are no other cases to consider!
When you look at such answers some questions may arise. Like: Do these three answers overlap, or are they truly disjoint? Prolog knows the answer. Simply repeat the actual goal and count the resulting answers:
?- L = [_,_,_], list_splitonstop(L, L1, L2), list_splitonstop(L, L1, L2).
(answers same as above)
So we get exactly the same answers. There is no inherent redundancy.
Another question might be: Does L
has always precisely one possible split? (In other words: Does there exist a functional dependency?)
We can get to this by asking for L
that have a different L1
and L2
:
?- L = [_,_,_], dif(L1-L2,L1x-L2x),
list_splitonstop(L, L1, L2), list_splitonstop(L, L1x, L2x).
L = [stop,stop,_A], L1 = [], L2 = [stop,_A], L1x = [stop], L2x = [_A]
; L = [stop,_A,stop], L1 = [], L2 = [_A,stop], L1x = [stop,_A], L2x = []
; L = [stop,stop,_A], L1 = [stop], L2 = [_A], L1x = [], L2x = [stop,_A]
; L = [_A,stop,stop], L1 = [_A], L2 = [stop], L1x = [_A,stop], L2x = []
; L = [stop,_A,stop], L1 = [stop,_A], L2 = [], L1x = [], L2x = [_A,stop]
; L = [_A,stop,stop], L1 = [_A,stop], L2 = [], L1x = [_A], L2x = [stop]
; false.
So, I may ask you now: Do you want above cases? If there are several occurrences of stop
? Clearly, you did not specify this and we need some more information from you. Prolog was at least helpful to identify such cases.
How to identify redundant answers.
In the case above we observed that there are no redundant answers. But how do they show up when they show up? Here is such an example: member/2
which is built-in and produces (sometimes) redundant answers and memberd/2
which does not have this redundancy. The actual question is:
How does a two-element list look like that has e
as an element/member?
?- Xs = [_,_], member(e, Xs).
Xs = [e,_A]
; Xs = [_A,e].
?- Xs = [_,_], member(e, Xs), member(e, Xs).
Xs = [e,_A]
; Xs = [e,e] % <--- redundant
; Xs = [e,e] % <--- redundant
; Xs = [_A,e].
?- Xs = [_,_], memberd(e, Xs).
Xs = [e,_A]
; Xs = [_A,e], dif(_A,e)
; false.
?- Xs = [_,_], memberd(e, Xs), memberd(e, Xs).
Xs = [e,_A]
; Xs = [_A,e], dif(_A,e)
; false.
If you are only interested in seeing those answers that permit redundancies, you can say in stead:
?- Xs = [_,_], member(e, Xs), \+ \+ call_nth(member(e, Xs), 2).
Xs = [e,_A]
; Xs = [_A,e].
In other words, all answers of member/2
permit such redundancies. Note that member/2
is not always prone to redundancy. In particular, if the list contains different (nonunifiable) elements, there are no redundancies at all. And this is a frequent use case.
?- Xs = [a,b], member(X, Xs), \+ \+call_nth(member(X, Xs),2).
false.
In fact, in this very case, that is when querying for X
, member/2
is probably more efficient than memberd/2
.