Prologue code for dividing parts of a list into consecutive even and odd parts
I was asked the following question:
Any list of integers can (unambiguously) be broken up into "parity runs", where each run is a (maximum) sequence of consecutive even or odd numbers in the original list. For example, the list
List = [8,0,4,3,7,2,-1,9,9]
can be broken up into [8, 0, 4]
, [3, 7]
, [2]
and [-1, 9, 9]
write the predicate paruns(List, RunList)
, which converts the list of numbers in the appropriate list runs parity. For example:
?- paruns([8,0,4,3,7,2,-1,9,9], RunList). RunList = [[8, 0, 4], [3, 7], [2], [-1, 9, 9]]
Here is the code I tried and it seems to work with the above example, thanks to one suggestion, but I have a problem where paruns([8,0,4], RunList).
it prints when I run it RunList = [[8,0,4],[]]
. Any suggestions would be appreciated :)
paruns([],[]).
paruns([Head | Tail], [E, O | S]) :-
even([Head | Tail], E, Last),
odd(Last, O, Last1),
paruns(Last1, S).
even([Head | Tail], [], [Head | Tail]) :-
Head mod 2 =:= 1.
even([Head | Tail], [Head | L], Last) :-
Head mod 2 =:= 0,
even(Tail, L, Last).
even([],[],[]).
odd([Head | Tail], [], [Head, Tail]) :-
Head mod 2 =:= 0.
odd([Head | Tail], [Head | L], Last) :-
Head mod 2 =:= 1,
odd(Tail, L, Last).
odd([],[],[]).
source to share
I think you only have a typo, in the first odd / 3 section. With the following code
paruns([],[]).
paruns([Head | Tail], [E, O | S]) :-
even([Head | Tail], E, Last),
odd(Last, O, Last1),
paruns(Last1, S).
even([Head | Tail], [], [Head | Tail]) :-
Head mod 2 =:= 1.
even([Head | Tail], [Head | L], Last) :-
Head mod 2 =:= 0,
even(Tail, L, Last).
even([],[],[]).
odd([Head | Tail], [], [Head | Tail]) :- % corrected
Head mod 2 =:= 0.
odd([Head | Tail], [Head | L], Last) :-
Head mod 2 =:= 1,
odd(Tail, L, Last).
odd([],[],[]).
I get
?- paruns([8,0,4,3,7,2,-1,9,9], RunList). RunList = [[8, 0, 4], [3, 7], [2], [-1, 9, 9]]
change
Ability to discard empty sequences (should only happen in the first or last position, I guess ... so perhaps a better approach would be to sanitize the results for these cases):
paruns([],[]).
%paruns([Head | Tail], [E, O | S]) :-
paruns([Head | Tail], R) :-
even([Head | Tail], E, Last),
odd(Last, O, Last1),
(E=[] -> R=[O|S] ; O=[] -> R=[E|S] ; R=[E,O|S]),
paruns(Last1, S).
source to share
The main attraction of Prolog is its relational nature . This means that we can often use the Prolog predicate in multiple ways, as long as we stick to reasonably general primitives.
In this particular case, since you are reasoning over integers , I highly recommend that you use your Prolog system CLP (FD) constraints in order to benefit from this generality.clpfdfor more information on this important declarative. function
Also, since you are describing a list, consider using DCG notation (dcg).
Here is a relational solution for your problem:
parity_runs ([], []) -> []. parity_runs ([E | Es], Os) -> [E], {E mod 2 # = 0}, parity_runs (Es, Os). parity_runs (Es, [O | Os]) -> [O], {O mod 2 # = 1}, parity_runs (Es, Os).
We can use it for the test case you posted where the list is specified:
? - phrase (parity_runs (Es, Os), [8,0,4,3,7,2, -1,9,9] ). Es = [8, 0, 4, 2], Os = [3, 7, -1, 9, 9]; false.
Moreover, we can also use it in other ways. For example, suppose the runs are known but the list is not specified:
? - phrase (parity_runs ( [2,4] , [1,3] ), Ls). Ls = [2, 4, 1, 3]; Ls = [2, 1, 4, 3]; Ls = [2, 1, 3, 4]; Ls = [1, 2, 4, 3]; Ls = [1, 2, 3, 4]; Ls = [1, 3, 2, 4]; false.
In addition, we can also send the most general request where nothing is known:
? - phrase (parity_runs (Es, Os), Ls). Es = Os, Os = Ls, Ls = []; Es = Ls, Ls = [_2012], Os = [], _2012 mod 2 # = 0; Es = Ls, Ls = [_256, _258], Os = [], _256 mod 2 # = 0, _258 mod 2 # = 0; Es = Ls, Ls = [_826, _832, _838], Os = [], _826 mod 2 # = 0, _832 mod 2 # = 0, _838 mod 2 # = 0; etc.
To calculate the answers correctly, we can use iterative deepening :
? - length (Ls, _) , phrase (parity_runs (Es, Os), Ls). Ls = Es, Es = Os, Os = []; Ls = Es, Es = [_168], Os = [], _168 mod 2 # = 0; Ls = Os, Os = [_550], Es = [], _550 mod 2 # = 1; Ls = Es, Es = [_770, _776], Os = [], _770 mod 2 # = 0, _776 mod 2 # = 0; Ls = [_770, _776], Es = [_770], Os = [_776], _770 mod 2 # = 0, _776 mod 2 # = 1; etc.
source to share
TL; DR:
Find the "right anchor" for the "hole" inmeta-predicate split_if_adj/3
and you're done!
This answer is based on:
-
clpfd (Constraint Logical programming by finite domains),
: - use_module ( library (clpfd) ).
-
: - use_module ( library (reif) ).
-
meta-predicate
split_if_adj/3
(defined in the previous answer) , -
and the reified condition predicate
dif_parity_t/3
:dif_parity_t(X, Y, T) :- (X+Y) mod 2 #= M, =(M,1,T). % reified term equality
So basically, we delegate the cumbersome and sometimes complex task of recursively processing lists for a higher-order predicate, which we tweak accordingly.
Example request:
?- split_if_adj(dif_parity_t, [8,0,4,3,7,2,-1,9,9], Rss). Rss = [[8,0,4],[3,7],[2],[-1,9,9]].
Please note that this request was successfully deterministic.
source to share