Shall I be pure or impure? Why even consider sacrificing logical-purity if we can save it easily!
Using memberd_t/3
and if_/3
, we define list_rset/2
and its left "twin" list_lset/2
:
list_rset([], []). % keep rightmost occurrences
list_rset([E|Es], Rs0) :-
if_(memberd_t(E, Es),
Rs0 = Rs,
Rs0 = [E|Rs]),
list_rset(Es, Rs).
list_lset([], []). % keep leftmost occurrences
list_lset([E|Es], Ls) :-
post_pre_lset(Es, [E], Ls). % uses internal auxilary predicate
post_pre_lset([], _, []).
post_pre_lset([E|Es], Pre, Ls0) :- % 2nd arg: look-behind accumulator
if_(memberd_t(E, Pre),
Ls0 = Ls,
Ls0 = [E|Ls]),
post_pre_lset(Es, [E|Pre], Ls).
Let's run some queries!
?- _Es = [1,2,3,1,2], list_lset(_Es, Ls), list_rset(_Es, Rs).
Ls = [1,2,3], Rs = [3,1,2]. % succeeds deterministically
In above query 1
precedes 2
both at the beginning and at the end of the list [1,2,3,1,2]
.
What if 1
precedes 2
at the beginning but follows it at the end (e.g., [1,2,3,2,1]
)?
?- _Es = [1,2,3,2,1], list_lset(_Es, Ls), list_rset(_Es, Rs).
Ls = [1,2,3], Rs = [3,2,1]. % succeeds deterministically
Next, we look at a more general list_rset/2
goal that uses a list containing variables only.
Thanks to @PauloMoura for his suggestion!
?- Es = [A,B,C,A,B], list_rset(Es,Rs).
Es = [C,C,C,C,C], Rs = [ C], A=B , B=C
; Es = [B,B,C,B,B], Rs = [C, B], A=B , dif(B,C)
; Es = [C,B,C,C,B], Rs = [ C,B], A=C , dif(B,C)
; Es = [A,C,C,A,C], Rs = [ A,C], dif(A,C), B=C
; Es = [A,B,C,A,B], Rs = [C,A,B], dif(A,B), dif(A,C), dif(B,C).
What's up with the residual goals (above)?
Without sufficient instantiation, dif/2
is not decidable.
To save logical soundness, the execution of the prolog-dif constraints is delayed.
Last, one more use-case: an "input" list Xs
that has both variables and ground terms.
?- Es = [A,B,z], list_rset(Es,Rs).
Es = [z,z,z], Rs = [ z], A=B , B=z
; Es = [B,B,z], Rs = [B, z], A=B , dif(B,z)
; Es = [z,B,z], Rs = [ B,z], A=z , dif(B,z)
; Es = [A,z,z], Rs = [A, z], dif(A,z), B=z
; Es = [A,B,z], Rs = [A,B,z], dif(A,B), dif(A,z), dif(B,z).
transform/3
fails becauseL2
(second argument) is never "driven" down to[]
which your base case assumes.L2
never changes. Trytransform([], _, []).
as your base case. – lurkerL2
more carefully. You are carrying the sameL2
throughout the recursion process. Since you're counting elements inL2
, the countS
of elements never changes throughout that process. It will not succeed on theS = 1
case. – lurker