I'm trying to write a predicate which "eliminates consecutive duplicates of list elements". My predicate looks like this:
compress([], []).
compress([X], [X]).
compress([X, X|Unpacked], [X|Rest]) :-
% pull an element off Unpacked
compress([X|Unpacked], [X|Rest]).
compress([X, Y|Unpacked], [X|Rest]) :-
dif(X, Y), % we've reached the end of this subsequence
compress([Y|Unpacked], Rest).
And it works great for mostly-instantiated queries:
compress([a, b], [a, b]) -> true
compress([a, a, b], [a, b]) -> true
compress([a, b, Z], X) -> Z = b, X = [a, b] OR X = [a, b, Z], dif(Z, b)
I just started learning Prolog this week, that last one is pretty cool!
This predicate, however, gives unsatisfactory results when used differently:
compress(X, [a, b]) -> never terminates
?- compress2(X, Y).
X = Y, Y = [] ;
X = Y, Y = [_904] ;
X = [_904, _904],
Y = [_904] ;
X = [_904, _904, _904],
Y = [_904] ;
X = [_904, _904, _904, _904],
Y = [_904] ;
X = [_904, _904, _904, _904, _904],
Y = [_904] .
(etc)
So, I wrote a wrapper around it which is better for those kinds of queries, it uses "generate and test" to exhaustively try all options for a given size of list before moving on to larger lists:
sizes(Large, Small) :-
between(0, inf, Large),
between(0, Large, Small).
compress2(Unpacked, Packed) :-
sizes(Large, Small),
length(Unpacked, Large),
length(Packed, Small),
compress(Unpacked, Packed).
This new predicate works great for general queries:
?- compress2(X, [a, b]).
X = [a, b] ;
X = [a, a, b] ;
X = [a, b, b] ;
X = [a, a, a, b] ;
X = [a, a, b, b] ;
(etc)
?- compress2(X, Y).
X = Y, Y = [] ;
X = Y, Y = [_658] ;
X = [_658, _658], Y = [_658] ;
X = Y, Y = [_1162, _1168], dif(_1162, _1168) ;
X = [_658, _658, _658], Y = [_658] ;
Both of the above eventually generate every alternative.
However, this predicate fails on the original queries:
compress2([a, b], [a, b]). -> returns true, then loops forever
It loops forever because I'm doing "generate and test", and the sizes
predicate generates every size. This works great until we find the answer, but once we've found the answer we backtrack and then generate an infinite number of sizes which are guaranteed to never work, they're too big.
So my question is, is there a pure way to make a compress
predicate which works for every query? Everything I try fixes one type of query while breaking others.