使用Prolog将单个列表拆分为三个

Moc*_*ing 5 prolog failure-slice

我正在尝试创建一个函数,将可变长度列表按顺序拆分为三个偶数长度列表.以下将其拆分为三个,但进程一次一个地将它们插入到每个列表中.

我想要的一个例子是:

[1, 2, 3, 4, 5] -> [1, 2], [3, 4], [5]
Run Code Online (Sandbox Code Playgroud)

另一个例子是:

[8, 7, 6, 5, 4, 3, 2, 1] -> [8, 7, 6], [5, 4, 3], [2, 1].
Run Code Online (Sandbox Code Playgroud)

以下代码通过一次插入一个列表来拆分它们:

div([], [], [], []).
div([X], [X], [], []).
div([X,Y], [X], [Y], []).
div([X,Y,Z|End], [X|XEnd], [Y|YEnd], [Z|ZEnd]):-
  div(End, XEnd, YEnd, ZEnd).
Run Code Online (Sandbox Code Playgroud)

此代码输出:

[1, 2, 3, 4, 5] -> [1, 4], [2, 5], [3]
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

fal*_*lse 5

@Boris的答案不会在第一个参数列表的长度未知时终止.要看到这一点,没有必要比的第一个目标更进一步:

div(L, L1, L2, L3) :-
    length(L, Len), false,
    % here you compute for example Len1 and Len2
    length(L1, Len1),
    length(L2, Len2),
    append(L1, L1_suffix, L),
    append(L2, L3, L1_suffix).

另一方面,您的原始程序具有相当不错的终止属性.cTI给出了以下最佳终止特性:

div(A,B,C,D) terminates_if b(A);b(B);b(C);b(D).
Run Code Online (Sandbox Code Playgroud)

换句话说,为了确保终止,您只需要一个参数(A或者BC或者D)作为有限和基础的具体列表(这b(..)意味着什么).这是一个非常强大的终止条件.这些论点不合适真的很可惜!为什么不概括你的程序?唯一的问题是它限制了列表元素.所以我将用_s 替换列表元素的所有变量名:

gdiv([], [], [], []).
gdiv([_], [_], [], []).
gdiv([_,_], [_], [_], []).
gdiv([_,_,_|End], [_|XEnd], [_|YEnd], [_|ZEnd]):-
  gdiv(End, XEnd, YEnd, ZEnd).
Run Code Online (Sandbox Code Playgroud)

该程序具有相同的终止属性.

唉,现在有点太笼统了.鲍里斯的解决方案现在可以改变用途:

divnew(Zs, As, Bs, Cs) :-
   gdiv(Zs, As, Bs, Cs),
   append(As, BsCs, Zs),
   append(Bs, Cs, BsCs).
Run Code Online (Sandbox Code Playgroud)

我表达同样的首选方式是:

divnew(Zs, As, Bs, Cs) :-
   gdiv(Zs, As, Bs, Cs),
   phrase( ( seq(As), seq(Bs), seq(Cs) ), Zs).
Run Code Online (Sandbox Code Playgroud)

请参阅其他答案以获得定义seq//1.