Prolog 写一个谓词将一个数字列表分成多个列表

Prolog 写一个谓词将一个数字列表分成多个列表,prolog,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]] 您只需按以下方式修改代码: same([X],[[X]]). same([H|T], Tail):- same(T,Tail1), finish(H, T

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

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

您只需按以下方式修改代码:

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

您声明不允许析取。但是,在构造输出列表时,必须在当前整数的符号和下一个整数(如果有)之间进行比较。不使用析取的可移植解决方案:

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]].
但从避免分离的意义上讲,这个解决方案值得花时间去开发或理解吗?可疑的使用if-then-else控件构造-->/2的解决方案更易于编写和理解,尽管可以说它不那么具有声明性

无论如何,一个或几个示例调用是非常有限的测试。快速检查实现(如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谓词采用谓词类型签名和可选选项列表。在这种情况下,签名将第一个参数指定为整数的输入列表,第二个参数指定为负整数或非负整数的列表。

欢迎使用。请更新您的问题以符合上概述的要点。不要问你还没有试图找到答案的问题来展示你的作品!这个问题的副本@joel76对不起,我之前已经检查过了,但是这个答案使用了;。如果不允许我使用;,如何编写谓词?如何使用可计算函子符号/1?它在ISO/IEC 13211-1:1995中。@重复该标准函数返回{-1,0,1},这会增加解决方案代码的大小,因为您需要子句来处理零,顺便说一句,这实际上是我上次编辑之前的解决方案。