Exercise 09 on this page http://www.ic.unicamp.br/~meidanis/courses/mc336/2009s2/prolog/problemas/ asks to create a predicate that packs repeated elements into sublists.
A straightforward solution is straightforward
pack([], []).
pack([H|T], [I|U]) :-
split(H, T, I, P),
pack(P, U).
where split is split(Head, Tail, HeadGroup, Rest)
is defined as
split(A, [], [A], []).
split(A, [B|T], [A], [B|T]) :- A \= B.
split(A, [A|T], [A|U], B) :- split(A, T, U, B).
which works fine and is pretty much in line with the example solution provided on the above-mentioned webpage.
Where this solution fails are the queries like pack(X, [[a], [b, b]]).
. The correspondence between two solution sets is bijective (for every A
in pack(A, B)
there is one and only one B
), so there must be a better solution.
One way to resolve it is to change the order of evaluation, helping prolog to pick non infinite branch depending on type of the argument like following
pack([], []).
pack(A, B) :-
( var(A) ->
A = [H|T],
B = [I|U],
pack(P, U),
split(H, T, I, P)
; A = [H|T],
B = [I|U],
split(H, T, I, P),
pack(P, U)
).
Two questions in this regard.
Firstly, this is unbelievably ugly, so is there maybe a better way to pick order of rules depending on argument type?
Secondly, probably much more complex question, is there a way to rewrite the solution without var(A)
, and if not why?
dif
it now can even solve the crazy stuff likepack(A, [X, [b]]).
. – Industrials