用于将列表的一部分拆分为连续的偶数和奇数部分的Prolog代码

时间:2017-03-30 12:45:47

标签: prolog

我收到了以下问题:

任何整数列表都可以(唯一地)分成“奇偶校验运行”,其中每次运行是原始列表中连续偶数或奇数的(最大)序列。例如,列表 List = [8,0,4,3,7,2,-1,9,9] 可分为[8, 0, 4][3, 7][2][-1, 9, 9] 编写谓词paruns(List, RunList),将数字列表转换为相应的奇偶校验运行列表。例如:

?- paruns([8,0,4,3,7,2,-1,9,9], RunList).
RunList = [[8, 0, 4], [3, 7], [2], [-1, 9, 9]] 

以下是我尝试的代码,它似乎与上面的示例案例一起使用,这要归功于一个建议,但我遇到了一个问题,即当我运行paruns([8,0,4], RunList).时,它会打印RunList = [[8,0,4],[]]。任何建议将不胜感激:)

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([],[],[]).

3 个答案:

答案 0 :(得分:3)

Prolog的一个主要吸引力在于其关系性。这意味着我们经常可以在几个方向中使用Prolog谓词,只要我们坚持使用足够的一般原语。

在这个具体案例中,由于您推理的是整数,我强烈建议您使用Prolog系统的 CLP(FD)约束来从这种普遍性中受益。有关此重要声明功能的详细信息,请参阅

此外,由于您正在描述列表,请考虑使用 DCG表示法)。

以下是您的任务的关系解决方案:

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).

我们可以将它用于您发布的测试用例,其中指定了列表:

?- 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.

此外,我们还可以在其他方向中使用它。例如,假设运行已知,但列表不是:

?- 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.

此外,我们还可以发布最常见的查询,其中一无所知:

?- 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.

公平地枚举答案,我们可以使用迭代深化

?- 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.

答案 1 :(得分:3)

<强> TL; DR: 找到&#34;右钉子&#34;对于&#34;洞&#34;在 split_if_adj/3中,您已完成!

这个答案基于:

因此,基本上,我们将递归处理列表的繁琐且有时棘手的任务委托给我们正确定制的高阶谓词。

示例查询:

?- 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]].

请注意,上述查询确定性成功。

答案 2 :(得分:2)

我认为你在第一个奇数/ 3条款中只有一个错字。使用以下代码

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([],[],[]).

我得到了

?- paruns([8,0,4,3,7,2,-1,9,9], RunList).
RunList = [[8, 0, 4], [3, 7], [2], [-1, 9, 9]] 

修改

丢弃空序列的可能性(应该仅在第一个或最后一个位置发生,我认为......所以可能更好的方法是对这些情况的结果进行消毒):

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).