Related
I am trying to write a predicate that will be true if X is a sublist of Y, without taking into account the first term and the last term of Y. For example, query listWithinList([b,c,d],[a,b,c,d,e]) would return True, but query listWithinList([b,c,d,e],[a,b,c,d,e]) would yield False because e, the last element of Y, should not be part of X.
Currently I have
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
but I am not sure how to change the code so that it does the same trick but without taking into account the first and last term of Y.
When you write _ in an argument to append, it refers to an arbitrary list. So arbitrary that its length is arbitrary too.
For example:
?- append(_, Suffix, [a, b, c]).
Suffix = [a, b, c] ;
Suffix = [b, c] ;
Suffix = [c] ;
Suffix = [] ;
false.
Here _ can stand for any of the lists [], [a], [a, b], [a, b, c]. But I don't need to tell you this. Prolog can tell you this if you give the anonymous variable _ a proper name instead:
?- append(Prefix, Suffix, [a, b, c]).
Prefix = [],
Suffix = [a, b, c] ;
Prefix = [a],
Suffix = [b, c] ;
Prefix = [a, b],
Suffix = [c] ;
Prefix = [a, b, c],
Suffix = [] ;
false.
In contrast, the term [_] stands not for an abitrary list. It stands for a list that definitely has exactly one element. That element (denoted _) is arbitrary.
For example:
?- append([_], Suffix, [a, b, c]).
Suffix = [b, c].
Or, again, with a proper variable name so we can see the binding:
?- append([X], Suffix, [a, b, c]).
X = a,
Suffix = [b, c].
All this is to say that the definition from the question:
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
Is close to being correct. But the two uses of _ don't "remove" one element each. They "remove" an arbitrary number of elements each. So you don't just get the middle of the list:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [] ;
Middle = [a] ;
Middle = [a, b] ;
Middle = [a, b, c] ;
Middle = [a, b, c, d] ;
Middle = [a, b, c, d, e] ;
Middle = [] ;
Middle = [b] ;
Middle = [b, c] ;
Middle = [b, c, d] ;
Middle = [b, c, d, e] ;
Middle = [] ;
Middle = [c] ;
Middle = [c, d] ;
Middle = [c, d, e] ;
Middle = [] ;
Middle = [d] ;
Middle = [d, e] ;
Middle = [] ;
Middle = [e] ;
Middle = [] ;
false.
If we want to "remove" lists of exactly one element from the front and the back, we must write [_]:
listWithinList(X, Y) :-
append([_], Y2, Y),
append(X, [_], Y2).
This now behaves like this:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [b, c, d] ;
false.
Additionally, note the difference between [_] and [_|_]. The former stands for a list of exactly one element. The latter stands for a list of one or more elements. In this case you don't want to "remove" more than one element, so using [_|_], like one of the other answers suggests, is absolute nonsense.
Finally, Prolog can suggest a further simplification to us:
?- append([X], Xs, Ys).
Ys = [X|Xs].
Appending a one-element list [X] and an arbitrary list Xs gives a list that we can also write as [X | Xs] without using append. So one of the append calls is not needed. I might write this predicate like this:
list_middle(List, Middle) :-
append([_First | Middle], [_Last], List).
And use it like this:
?- list_middle([a, b, c, d, e], Middle).
Middle = [b, c, d] ;
false.
Or like this:
?- list_middle(List, [1, 2, 3]).
List = [_2658, 1, 2, 3, _2664].
Grammars are very intuitive for such tasks. Just describe what we have:
list_within(Xs, Ys) :-
phrase(( [_First], seq(Ys), [_Last] ), Xs).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
That is, first the element _First, then the sequence Ys, and finally the element _Last.
Due to how lists are represented in Prolog, you can easily remove the first element by destructuring it as its head and tail, and unifying the result with tail, as follows:
tail([_|L], L).
On success, the predicates unifies the second parameter with the tail of the first.
To remove the last element, you can say that your input list is the result of appending a prefix to a list of one element (whose value is not important):
butlast(List, Prefix) :-
append(Prefix, [_LastValue], List).
You can combine them both to remove both extremities:
chop(List, Middle):
tail(List, Tail),
butlast(Tail, Middle).
Here is my approach:
First: Create all combinations of the List that are acceptable when the first letter is removed and last letter is removed.
listWithinList(M,L):-
append([_|_],L2,L),
append(S,[_|_],L2),
The first append removes the first element from the list, and the second append removes the last element from the list. The combinations of List are stored in S.
Second: We use the same predicate to check if M is same as any of the combinations in S.
same(L1,L2):-
L1==L2.
Putting the code together:
listWithinList(M,L):-
append([_|_],L2,L),
append(S,[_|_],L2),
( same(M,S)->write(S),
write('This combination is correct.') ).
same(L1,L2):-
L1==L2.
Examples:
?-listWithinList([b,c,d],[a,b,c,d,e]).
[b, c, d]This combination is correct.
1true
false
?-listWithinList([b,c,d,e],[a,b,c,d,e]).
false
?-listWithinList([a,b,c,d,e],[a,b,c,d,e]).
false
I'm new to Prolog and trying to do this question. We have a list
List = [a,a,a,a,b,c,c,a,a,d,e,e,e,e]
I want to pack it into sub-lists of similar elements.
Pack( [a,a,a,a,b,c,c,a,a,d,e,e,e,e], Sublists)
should give
Sublists = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]]
This is what I have tried so far:
pack([],[],[]).
pack([H],[H],[H]).
pack([H,H1|T],Z,X):- H==H1 , append([H],Z,Z1) , pack([H1|T],Z1,X).
pack([H,H1|T],Z,X):- H=\=H1 , append([H],Z,Z1) ,
append(Z1,X,Xs) , pack([H1|T],Z1,Xs).
Below is the error:
Arithmetic: `a/0' is not a function
In:
[4] a=\=b
[3] pack([a,b|...],[a,a],_1608) at line 13
[2] pack([a,a|...],[a],_1688) at line 13
[1] pack([a,a|...],[],_1762) at line 13
Thanks in advance. I'm trying to solve these problems:
P-99: Ninety-Nine Prolog Problems.
You can approach this kind of problem with simple list processing and using SWI Prolog's dif/2 to provide a general solution:
pack([], []). % packing empty is empty
pack([X], [[X]]). % packing a single element
pack([X,X|T], [[X|PH]|PT]):- % rule for packing when next two terms are the same
pack([X|T], [PH|PT]).
pack([X,Y|T], [[X]|PT]):- % rule for different term
dif(X, Y),
pack([Y|T], PT).
2 ?- pack([a,a,a,a,b,c,c,a,a,d,e,e], L).
L = [[a, a, a, a], [b], [c, c], [a, a], [d], [e, e]] ;
false.
3 ?- pack(L, [[a,a,a], [b,b], [c]]).
L = [a, a, a, b, b, c] ;
false.
4 ?-
Note that lurker's solution still has some performance issues. See the ; false for each solution? This is an indication that Prolog still retains some memory (called a choice point - actually there may be even several such choice points). For many cases however, no such choice point is needed. Here is a solution that overcomes that problem (The name group in place of pack is quite common in the context of Haskell)
group([], []).
group([E|Es], [[E|Gs]|Gss]) :-
igroup(Es, E, Gs, Gss).
igroup([], _, [], []).
igroup([E|Es], F, Gs1, Gss1) :-
( E\=F
-> Gs1=[], Gss1=[[E|Gs2]|Gss2]
; E==F
-> Gs1=[E|Gs2], Gss1=Gss2
; E=F,
Gs1=[E|Gs2], Gss1=Gss2
; dif(E, F),
Gs1=[], Gss1=[[E|Gs2]|Gss2]
),
igroup(Es, E, Gs2, Gss2).
Note how the testing for the equality of E and F is split into four cases:
First E \= F which means that both are definitely different.
Then E == F which means that both are definitely identical.
Then E = F which is the general case of equality, and
dif(E, F) which is the case of general inequality
For the last two cases there is no -> because both may be true.
Since it is quite cumbersome to maintain so many cases, there is library(reif)
for
SICStus and
SWI which permits to write the same more compactly:
igroup([], _, [], []).
igroup([E|Es], F, Gs1, Gss1) :-
if_(E = F
, ( Gs1 = [E|Gs2], Gss1 = Gss2 )
, ( Gs1 = [], Gss1 = [[E|Gs2]| Gss2] )),
igroup(Es, E, Gs2, Gss2).
The error you got is because =\=/2 is true if expr1 is evaluates to a number not equal to expr2 . Instead you can use \=\2 which evaluates \+term1=term2. ==/2 evaluates to term1 equivalent to term2, =:=/ is true if expr1 is a number which is equal to expr2. One more mistake I found in your code is you're not clearing the Intermediate List. You have to flush the values in it after you have added the similar elements list to your Sublists list. I have used cut ! to reduce backtracking. Instead, if you write mutually exclusive predicates, it's better.
I have edited your code:
pack1([],[],[]).
pack1([H],L,[Z]):- append([H],L,Z),!.
pack1([H,H1|T],Z,X):- H == H1 , append([H],Z,Z1) , pack1([H1|T],Z1,X),!.
pack1([H,H1|T],Z,[Z1|Zs]):- H\=H1 ,append([H],Z,Z1) ,pack1([H1|T],[],Zs),!.
Output:
?-pack1([a,a,a,a,b,c,c,a,a,d,e,e,e,e],[],Z).
Z=[[a, a, a, a], [b], [c, c], [a, a], [d], [e, e, e, e]]
?-pack1([a,a,a,a,b,c,1,c,a,a,d,e,e,e,e],[],Z).
Z= [[a, a, a, a], [b], [c], [1], [c], [a, a], [d], [e, e, e, e]]
?-pack1([],[],Z).
Z= []
Hope this helps.
without using dif/2
my_pack([],[[]]).
my_pack([X], [[X]]).
my_pack([X,X|L], [F|R]) :- my_pack([X|L], [F1|R]), append([X], F1, F).
my_pack([X|L], [F|R]) :- my_pack(L, R), append([X], [], F).
I am having trouble starting this Prolog program that takes two lists and returns true if all members in the first list are members of the second list, and false otherwise.
Examples:
?- members([a, c], [a, b, c, d])
true
?- members([d, a, c, a], [a, b, c, d, e])
true
?- members([b, e], [a, b, c, d])
false
?- members([], [a, b, c, d])
true
How do I go about doing this? Any help is appreciated.
You can use maplist on this kind of problem since it follows a standard recursive list traversal:
mem(L, X) :- memberchk(X, L).
subset(S, L) :- maplist(mem(L), S).
Results:
| ?- subset([a,c], [a,b,c,d]).
yes
| ?- subset([c,a], [a,b,c,d]).
yes
| ?- subset([e], [a,b,c,d]).
no
| ?- subset([], [a,b,c,d]).
yes
| ?- subset(S, [a,b,c,d]), S=[_|_].
S = [a] ? ;
S = [a,a] ? ;
S = [a,a,a] ? ;
...
Note that the original problem definition does not rule out the case where the subset can have duplicate elements from the superset. If you want to restrict the subsets to having counts of elements less than or equal to the superset, you can use select/3:
subset([], _).
subset([X|Xs], L) :-
select(X, L, L1),
subset(Xs, L1).
Results:
| ?- subset([a,c], [a,b,c,d,e]).
true ? ;
no
| ?- subset([a,f], [a,b,c,d,e]).
no
| ?- subset([a,a], [a,b,c,d,e]).
no
| ?- subset(S, [a,b,c]), S=[_|_].
S = [a] ? ;
S = [a,b] ? ;
S = [a,b,c] ? ;
S = [a,c] ? ;
S = [a,c,b] ? ;
S = [b] ? ;
S = [b,a] ? ;
...
S = [c,b] ? ;
S = [c,b,a] ? ;
no
You'll note that the list [c,b,a] is considered a different list in Prolog versus [a,b,c] so it is a separate solution. If you want to make the lists behave truly as sets, then that's a different solution.
"We tried nothing and we're all out of ideas"
I would suggest you find a predicate that does that, then look at its implementation.
$ swipl
?- subset([a, c], [a, b, c, d]).
true.
?- subset([d, a, c, a], [a, b, c, d, e]).
true.
?- subset([b, e], [a, b, c, d]).
false.
?- subset([], [a, b, c, d]).
true.
It is documented here: http://www.swi-prolog.org/pldoc/doc_for?object=subset/2
You can click on the little yellow circle with the colon and the dash to see how it is implemented: http://www.swi-prolog.org/pldoc/doc/SWI/library/lists.pl?show=src#subset/2
713 subset([], _) :- !.
714 subset([E|R], Set) :-
715 memberchk(E, Set),
716 subset(R, Set).
This definition is about the same as:
maplist([M]>>memberchk(M, Set), Subset)
This definition always succeeds or fails only once. This is by design.
It could also have been implemented like this:
maplist([M]>>member(M, Set), Subset)
And it behaves like the suggestion in the comments:
?- maplist([M]>>member(M, [a,b]), Subset).
Subset = [] ;
Subset = [a] ;
Subset = [a, a] ;
Subset = [a, a, a] ;
Subset = [a, a, a, a] .
?- length(Subset, _), maplist([M]>>member(M, [a,b]), Subset).
Subset = [] ;
Subset = [a] ;
Subset = [b] ;
Subset = [a, a] ;
Subset = [a, b] ;
Subset = [b, a] ;
Subset = [b, b] ;
Subset = [a, a, a] ;
Subset = [a, a, b] .
This question was asked but there are no answers: here. I read the comments and tried to implement in both ways, but there are more problems that I don't understand.
I first tried the easy way that doesn't keep original order:
list_repeated(L, Ds) :-
msort(L, S),
sorted_repeated(S, Ds).
sorted_repeated([], []).
sorted_repeated([X|Xs], Ds) :-
first(Xs, X, Ds).
first([], _, []).
first([X|Xs], X, [X|Ds]) :-
more(Xs, X, Ds).
first([X|Xs], Y, Ds) :-
dif(X, Y),
first(Xs, X, Ds).
more([], _, []).
more([X|Xs], X, Ds) :-
more(Xs, X, Ds).
more([X|Xs], Y, Ds) :-
dif(X, Y),
first(Xs, X, Ds).
Once the list is sorted without removing duplicates, using first and more I add the element to the second argument if it occurs at least twice and skip all consecutive copies of the element.
This is not working properly because if I have:
?- list_duplicates([b,a,a,a,b,b], Ds).
I get answer [a,b] instead of [b,a] and also I get ; false after the answer.
I also tried another way, but this doesn't work because the accumulator is immutable?
list_duplicates(L, Ds) :-
ld_acc(L, [], Ds).
ld_acc([], _, []).
ld_acc([X|Xs], Acc, Ds) :-
( memberchk(X, Acc)
-> Ds = [X|Ds0],
ld_acc(Xs, Acc, Ds0)
; Acc1 = [X|Acc],
ld_acc(Xs, Acc1, Ds)
).
This cannot work because when I check that an element is member of accumulator I remove only one occurrence of each element: if I have three times the same element in the first argument, I am left with two. If I could change the element in the accumulator then I could maybe put a counter on it? In the first version I used different states, first and more, but here I have to attach state to the elements of the accumulator, is that possible?
A plea for purity
When programming in Prolog, a major attraction is the generality we enjoy from pure relations.
This lets us use our code in multiple directions, and reason declaratively over our programs and answers.
You can enjoy these benefits if you keep your programs pure.
Possible solution
As always when describing lists, also consider using DCG notation. See dcg for more information.
For example, to describe the list of duplicates in a pure way, consider:
list_duplicates([]) --> [].
list_duplicates([L|Ls]) -->
list_duplicates_(Ls, L),
list_duplicates(Ls).
list_duplicates_([], _) --> [].
list_duplicates_([L0|Ls], L) -->
if_(L0=L, [L], []),
list_duplicates_(Ls, L).
This uses if_//3 to retain generality and determinism (if applicable).
Examples
Here are a few example queries and answers. We start with simple ground cases:
?- phrase(list_duplicates([a,b,c]), Ds).
Ds = [].
?- phrase(list_duplicates([a,b,a]), Ds).
Ds = [a].
Even the most impure version will be able to handle these situations correctly. So, slightly more interesting:
?- phrase(list_duplicates([a,b,X]), Ds).
X = a,
Ds = [a] ;
X = b,
Ds = [b] ;
Ds = [],
dif(X, b),
dif(X, a).
Pretty nice, isn't it? The last part says: Ds = [] is a solution if X is different from b and a. Note the pure relation dif/2 automatically appears in these residual goals and retains the relation's generality.
Here is an example with two variables:
?- phrase(list_duplicates([X,Y]), Ds).
X = Y,
Ds = [Y] ;
Ds = [],
dif(Y, X).
Finally, consider using iterative deepening to fairly enumerate answers for lists of arbitrary length:
?- length(Ls, _), phrase(list_duplicates(Ls), Ds).
Ls = Ds, Ds = [] ;
Ls = [_136],
Ds = [] ;
Ls = [_136, _136],
Ds = [_136] ;
Ls = [_156, _162],
Ds = [],
dif(_162, _156) ;
Ls = Ds, Ds = [_42, _42, _42] ;
Ls = [_174, _174, _186],
Ds = [_174],
dif(_186, _174) .
Multiple occurrences
Here is a version that handles arbitrary many occurrences of the same element in such a way that exactly a single occurrence is retained if (and only if) the element occurs at least twice:
list_duplicates(Ls, Ds) :-
phrase(list_duplicates(Ls, []), Ds).
list_duplicates([], _) --> [].
list_duplicates([L|Ls], Ds0) -->
list_duplicates_(Ls, L, Ds0, Ds),
list_duplicates(Ls, Ds).
list_duplicates_([], _, Ds, Ds) --> [].
list_duplicates_([L0|Ls], L, Ds0, Ds) -->
if_(L0=L, new_duplicate(L0, Ds0, Ds1), {Ds0 = Ds1}),
list_duplicates_(Ls, L, Ds1, Ds).
new_duplicate(E, Ds0, Ds) -->
new_duplicate_(Ds0, E, Ds0, Ds).
new_duplicate_([], E, Ds0, [E|Ds0]) --> [E].
new_duplicate_([L|Ls], E, Ds0, Ds) -->
if_(L=E,
{ Ds0 = Ds },
new_duplicate_(Ls, E, Ds0, Ds)).
The query shown by #fatalize in the comments now yields:
?- list_duplicates([a,a,a], Ls).
Ls = [a].
The other examples yield the same results. For instance:
?- list_duplicates([a,b,c], Ds).
Ds = [].
?- list_duplicates([a,b,a], Ds).
Ds = [a].
?- list_duplicates([a,b,X], Ds).
X = a,
Ds = [a] ;
X = b,
Ds = [b] ;
Ds = [],
dif(X, b),
dif(X, a).
?- list_duplicates([X,Y], Ds).
X = Y,
Ds = [Y] ;
Ds = [],
dif(Y, X).
I leave the case ?- list_duplicates(Ls, Ls). as an exercise.
Generality: Multiple directions
Ideally, we want to be able to use a relation in all directions.
For example, our program should be able to answer questions like:
What does a list look like if its duplicates are [a,b]?
With the version shown above, we get:
?- list_duplicates(Ls, [a,b]).
nontermination
Luckily, a very simple change allows as to answer such questions!
One such change is to simply write:
list_duplicates(Ls, Ds) :-
length(Ls, _),
phrase(list_duplicates(Ls, []), Ds).
This is obviously declaratively admissible, because Ls must be a list. Operationally, this helps us to enumerate lists in a fair way.
We now get:
?- list_duplicates(Ls, [a,b]).
Ls = [a, a, b, b] ;
Ls = [a, b, a, b] ;
Ls = [a, b, b, a] ;
Ls = [a, a, a, b, b] ;
Ls = [a, a, b, a, b] ;
Ls = [a, a, b, b, a] ;
Ls = [a, a, b, b, b] ;
Ls = [a, a, b, b, _4632],
dif(_4632, b),
dif(_4632, a) ;
etc.
Here is a simpler case, using only a single element:
?- list_duplicates(Ls, [a]).
Ls = [a, a] ;
Ls = [a, a, a] ;
Ls = [a, a, _3818],
dif(_3818, a) ;
Ls = [a, _3870, a],
dif(_3870, a) ;
Ls = [_4058, a, a],
dif(a, _4058),
dif(a, _4058) ;
Ls = [a, a, a, a] ;
etc.
Maybe even more interesting:
What does a list without duplicates look like?
Our program answers:
?- list_duplicates(Ls, []).
Ls = [] ;
Ls = [_3240] ;
Ls = [_3758, _3764],
dif(_3764, _3758) ;
Ls = [_4164, _4170, _4176],
dif(_4176, _4164),
dif(_4176, _4170),
dif(_4170, _4164) .
Thus, the special case of a list where all elements are distinct naturally exists as a special case of the more general relation we have implemented.
We can use this relation to generate answers (as shown above), and also to test whether a list consists of distinct elements:
?- list_duplicates([a,b,c], []).
true.
?- list_duplicates([b,b], []).
false.
Unfortunately, the following even more general query still yields:
?- list_duplicates([b,b|_], []).
nontermination
On the plus side, if the length of the list is fixed, we get in such cases:
?- length(Ls, L), maplist(=(b), Ls),
( true ; list_duplicates(Ls, []) ).
Ls = [],
L = 0 ;
Ls = [],
L = 0 ;
Ls = [b],
L = 1 ;
Ls = [b],
L = 1 ;
Ls = [b, b],
L = 2 ;
Ls = [b, b, b],
L = 3 ;
Ls = [b, b, b, b],
L = 4 .
This is some indication that the program indeed terminates in such cases. Note that the answers are of course now too general.
Efficiency
It is well known in high-performance computing circles that as long as your program is fast enough, its correctness is barely worth considering.
So, the key question is of course: How can we make this faster?
I leave this is a very easy exercise. One way to make this faster in specific cases is to first check whether the given list is sufficiently instantiated. In that case, you can apply an ad hoc solution that fails terribly in more general cases, but has the extreme benefit that it is fast!
So as far as I can tell, you were on the right track with the accumulator, but this implementation definitely works as you want (assuming you want the duplicates in the order they first appear in the list).
list_duplicates(Input,Output) is just used to wrap and initialise the accumulator.
list_duplicates(Accumulator,[],Accumulator) unifies the accumulator with the output when we have finished processing the input list.
list_duplicates(Accumulator,[H|T],Output) says "if the head (H) of the input list is in the rest of the list (T), and is not in the Accumulator already, put it at the end of the Accumulator (using append), then recurse on the tail of the list".
list_duplicates(Accumulator,[_|T],Output) (which we only get to if either the head is not a duplicate, or is already in the Accumulator) just recurses on the tail of the list.
list_duplicates(Input,Output) :-
once(list_duplicates([],Input,Output)).
list_duplicates(Accumulator,[],Accumulator).
list_duplicates(Accumulator,[H|T],Output) :-
member(H,T),
\+member(H,Accumulator),
append(Accumulator,[H],NewAccumulator),
list_duplicates(NewAccumulator,T,Output).
list_duplicates(Accumulator,[_|T],Output) :-
list_duplicates(Accumulator,T,Output).
You could also recurse in list_duplicates(Accumulator,[H|T],Output) with list_duplicates([H|Accumulator],T,Output) and reverse in the wrapper, looking like this:
list_duplicates(Input,Output) :-
once(list_duplicates([],Input,ReverseOutput)),
reverse(ReverseOutput,Output).
list_duplicates(Accumulator,[],Accumulator).
list_duplicates(Accumulator,[H|T],Output) :-
member(H,T),
\+member(H,Accumulator),
list_duplicates([H|Accumulator],T,Output).
list_duplicates(Accumulator,[_|T],Output) :-
list_duplicates(Accumulator,T,Output).
The once call in the wrapper prevents the false output (or in this case, partial duplicate lists due to a lack of guards on the second rule).
I'm new in Prolog.
I have a problem about predicate prefix but a little bit different.
I want to get a prefix of a list but until an element
The list can have repeat elements.
An example:
prefix(Element, List, Prefix)
prefix(c, [a,b,c,d,e,f], [a, b])
The element is not included.
What I have so far is this
prefix(X, [X|T], []).
prefix(X, [Y|T], [Y|Z]):-
prefix(X, T, Z).
But it does not work.
L = [a,b,c] ? prefix(b, L, Prefix).
no
?-
Thanks
With dif/2 you can explicitly state that for any member X preceding Element, X \== Element:
prefix(Element, [Element|_], []).
prefix(Element, [Head|List], [Head|Prefix]) :-
dif(Element, Head),
prefix(Element, List, Prefix).
or equally, because I wanted to use append/3 in the first iteration of my answer:
prefix(Element, List, Prefix) :-
append(Prefix, [Element|_Suffix], List),
maplist(dif(Element), Prefix).
For the suffix it is basically the same:
suffix(Element, List, Suffix) :-
append(_Prefix, [Element|Suffix], List),
maplist(dif(Element), Suffix).
If you don't want to use maplist(dif(Element), List):
all_dif(_, []).
all_dif(X, [H|T]) :- dif(X, H), all_dif(X, T).
Here is a solution using Definite Clause Grammars dcg and the non-terminal all_seq//2:
prefix(X, Xs, Ys) :-
phrase( ( all_seq(dif(X), Ys), [X], ... ), Xs).
... --> [] | [_], ... .
So the grammar (within phrase/2) reads:
There is
1. an initial sequence Ys with all elements different to X, followed by 2. X, followed by 3. anything.
There is still a downside, which is often the case when using DCGs: The implementation is not as determinate as it could be and thus leaves superfluous choicepoints around.
prefix(X,[X|T],[]).
prefix(X,[Y|T],Z) :- prefix(X,T,M) , Z = [Y|M].
output:
?- L = [a,b,c,d,e,f] , prefix(d,L,G). L = [a, b, c, d, e, f], G = [a,
b, c] .
?- L = [a,b,c,d,e,f] , prefix(e,L,G). L = [a, b, c, d, e, f], G = [a,
b, c, d] .
EDIT #1
the original code is working , use (,) instead of (?) as following.
prefix(X,[X|T],[]).
prefix(X,[Y|T],[Y|Z]) :- prefix(X,T,Z).
output:
?- prefix(d , [a,b,c,d,e] , G). G = [a, b, c]
?- L = [a,b,c] , prefix(b, L, Prefix).
L = [a, b, c],
Prefix = [a] .
EDIT #2
as user false mentioned in comment, I can confirm that you are right, but in my solution, I assume that the list contains unique elements:
prefix(d,[d,d],[d]) succeeds - it should fail ,