I have a problem with returning an answer to Problem 9 of P-99: Ninety-Nine Prolog Problems:
Pack consecutive duplicates of list elements into sublists. If a list contains repeated elements they should be placed in separate sublists.
Sample query with expected results:
?- pack([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).
X = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]].
I managed to pack elements in sublists but I don't know how to return an answer.
Here's my code:
pack(X,Y) :- pack(X,[],Y).
pack([H,H|T],Acc,X) :- pack([H|T],[H|Acc],X).
pack([H,H1|T], Acc, X) :-
H\=H1,
Acc1=[H|Acc],
append(X, [Acc1], X1),
pack([H1|T],[],X1).
pack([H], Acc, X) :-
Acc1=[H|Acc],
append(X, [Acc1], X1).
Here's a query run in trace mode:
?- trace, pack([a,a,a,a,b,c,c],X).
Call: (6) pack([a, a, a, a, b, c, c], _G986) ? creep
Call: (7) pack([a, a, a, a, b, c, c], [], _G986) ? creep
Call: (8) pack([a, a, a, b, c, c], [a], _G986) ? creep
Call: (9) pack([a, a, b, c, c], [a, a], _G986) ? creep
Call: (10) pack([a, b, c, c], [a, a, a], _G986) ? creep
Call: (11) a\=b ? creep
Exit: (11) a\=b ? creep
Call: (11) _G1100=[a, a, a, a] ? creep
Exit: (11) [a, a, a, a]=[a, a, a, a] ? creep
Call: (11) lists:append(_G986, [[a, a, a, a]], _G1105) ? creep
Exit: (11) lists:append([], [[a, a, a, a]], [[a, a, a, a]]) ? creep
Call: (11) pack([b, c, c], [], [[a, a, a, a]]) ? creep
Call: (12) b\=c ? creep
Exit: (12) b\=c ? creep
Call: (12) _G1109=[b] ? creep
Exit: (12) [b]=[b] ? creep
Call: (12) lists:append([[a, a, a, a]], [[b]], _G1114) ? creep
Exit: (12) lists:append([[a, a, a, a]], [[b]], [[a, a, a, a], [b]]) ? creep
Call: (12) pack([c, c], [], [[a, a, a, a], [b]]) ? creep
Call: (13) pack([c], [c], [[a, a, a, a], [b]]) ? creep
Call: (14) _G1127=[c, c] ? creep
Exit: (14) [c, c]=[c, c] ? creep
Call: (14) lists:append([[a, a, a, a], [b]], [[c, c]], _G1132) ? creep
Exit: (14) lists:append([[a, a, a, a], [b]], [[c, c]], [[a, a, a, a], [b], [c, c]]) ? creep
Exit: (13) pack([c], [c], [[a, a, a, a], [b]]) ? creep
Exit: (12) pack([c, c], [], [[a, a, a, a], [b]]) ? creep
Exit: (11) pack([b, c, c], [], [[a, a, a, a]]) ? creep
Exit: (10) pack([a, b, c, c], [a, a, a], []) ? creep
Exit: (9) pack([a, a, b, c, c], [a, a], []) ? creep
Exit: (8) pack([a, a, a, b, c, c], [a], []) ? creep
Exit: (7) pack([a, a, a, a, b, c, c], [], []) ? creep
Exit: (6) pack([a, a, a, a, b, c, c], []) ? creep
X = [] .
I imagine there should be additional line at the end of last rule to somehow bind the result to the input but I have no idea how to do it.
Something like this ought to work, I think:
I think this one will work. I used an "accumulator" for gathering the duplicate member sublists.
Results:
here is the minimal modification required to make your code working: add a 'return only' variable, to 'emerge' the result from the inner working append to top level:
test:
as you have seen, there are plenty of alternative algorithms available: here is mine, I attempted to make it simple as possible:
its behaviour is most similar to 'naive insertion sort': take the front element and put it at the right place. To avoid appending the element, I use an accumulator, to be reversed at the end (as most of other answers here).
edit I guess, reading other answers, that someone else (like me) found your code difficult to understand. The cause could be that you are mixing 'input/output' arguments. As a stylistic choice, Prologgers usually stick to 'input first, output last'. This not always make sense (after all, Prolog is about relations, not functions), but nevertheless is often an useful, simple technique to follow.
HTH
If you use SWI-Prolog, with module(library(lambda)) and foldl, you can write :
Module lambda.pl can be found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl
Here's how you could do it in a logically pure way: Use the meta-predicate
splitlistIfAdj/3
in combination withdif/3
, a reified variant of prolog-dif. Let's do some queries right now!Unlike impure code, the implementation is monotone and can be used with non-ground terms:
Note that more general queries like the following one also give logically sound answers:
First things first: you have a singleton variable warning about X1:
This whole rule reduces to this:
That surely isn't what you want, but looking at what you've got here I'm not sure what you do want. For one thing I wouldn't approach the problem with
append/3
. Your solution actually generates lists of distinct values, which tells me there's been a pretty severe misfire somewhere.I wish I could see the problem, because in the trace I see you're building up the result correctly. Someone with more insight may furnish a fix for your typo.
Anyway, this is what I came up with:
In fact a difference list solution would allow prepending without using
append/3
or usingreverse/2
at the end, but I don't have one in my back pocket.