编写谓词,将数字列表分成多个列表

时间:2019-03-17 15:42:41

标签: prolog

将数字列表划分为多个列表,每个列表都是原始列表中最长的负数或非负数序列。 例如:

?- plus_or_minus([278,31,-3,-6,18,0,0,5,101,-45,0], RunList). 
RunList = [[278,31], [-3,-6], [18,0,0,5,101], [-45],[0]]  

2 个答案:

答案 0 :(得分:0)

您只需以这种方式修改代码:

same([X],[[X]]).

same([H|T], Tail):-
    same(T,Tail1),
    finish(H,  Tail1, Tail).

finish(H,  [[X| T1]|Tail], New_Tail):-
    H >= 0,
    X >= 0
    New_Tail = ... .

finish(H,  [[X| T1]|Tail], New_Tail):-
    H >= 0,
    ...
    ....

finish(H,  [[X| T1]|Tail], New_Tail):-
    ...
    ...
    ...

finish(H, [[X| T1]|Tail], New_Tail):-
    ... 
    ... 
    ...

答案 1 :(得分:0)

您声明不允许析取。但是,在构造输出列表时,必须在当前整数的 sign 与下一个整数(如果有)之间进行比较。无需分离的便携式解决方案:

plus_or_minus([], []).
plus_or_minus([I| Tail1], [[I|Is]| Tail2]) :-
    integer_sign(I, Sign),
    plus_or_minus_sign(Sign, Tail1, Is, Tail2).

plus_or_minus_sign(-1, Tail1, Is, Tail2) :-
    plus_or_minus_sign_negative(Tail1, Is, Tail2).
plus_or_minus_sign(+1, Tail1, Is, Tail2) :-
    plus_or_minus_sign_positive(Tail1, Is, Tail2).

plus_or_minus_sign_negative([], [], []).
plus_or_minus_sign_negative([I| Tail1], Is, Tail2) :-
    integer_sign(I, Sign),
    plus_or_minus_sign_negative_same(Sign, I, Tail1, Is, Tail2).

plus_or_minus_sign_negative_same(-1, I, Tail1, [I| Is], Tail2) :-
    plus_or_minus_sign(-1, Tail1, Is, Tail2).
plus_or_minus_sign_negative_same(+1, I, Tail1, [], [[I| Is]| Tail2]) :-
    plus_or_minus_sign(+1, Tail1, Is, Tail2).

plus_or_minus_sign_positive([], [], []).
plus_or_minus_sign_positive([I| Tail1], Is, Tail2) :-
    integer_sign(I, Sign),
    plus_or_minus_sign_positive_same(Sign, I, Tail1, Is, Tail2).

plus_or_minus_sign_positive_same(-1, I, Tail1, [], [[I| Is]| Tail2]) :-
    plus_or_minus_sign(-1, Tail1, Is, Tail2).
plus_or_minus_sign_positive_same(+1, I, Tail1, [I| Is], Tail2) :-
    plus_or_minus_sign(+1, Tail1, Is, Tail2).

integer_sign(Integer, Sign) :-
    catch(Sign is abs(Integer)//Integer, _, Sign = 1).

此解决方案利用了大多数prolog系统实现的第一参数索引编制功能,避免了虚假的选择点。

通话示例:

?- plus_or_minus([278,31,-3,-6,18,0,0,5,101,-45,0], RunList).
RunList = [[278, 31], [-3, -6], [18, 0, 0, 5, 101], [-45], [0]].

但是,从避免歧义的角度来看,这种解决方案是否值得花时间进行 develop 理解?疑。使用if-then-else控制结构->/2的解决方案尽管声明性较低,但更容易编写和理解。

无论如何,一个样本调用或其中的几个采样都是相当有限的测试。 QuickCheck实施(例如Logtalk lgtunit工具提供的实施)可以在此处提供帮助:

?- lgtunit::quick_check(plus_or_minus(+list(integer), -list(types([list(negative_integer),list(non_negative_integer)])))).
% 100 random tests passed
true.

?- lgtunit::quick_check(plus_or_minus(+list(integer), -list(types([list(negative_integer),list(non_negative_integer)]))), [n(1000)]).
% 1000 random tests passed
true.

lgtunit::quick_check/1-2谓词带有谓词类型签名和可选的选项列表。在这种情况下,签名将第一个参数指定为整数的输入列表,第二个参数指定为负整数或非负整数的列表。