在Prolog中将一个列表拆分为两个长度相等的列表

在Prolog中将一个列表拆分为两个长度相等的列表,prolog,Prolog,我正在用Prolog编写一个谓词,将一个列表分成两个长度相等的列表。例如: div([1,2,3,4] , X , Y). X = [1,2]. Y = [3,4]. 这是我的代码,但不起作用: div(L , L1 , L):- length(L) == length(L1). div([ H | T ] , [ H | T1] , L2):- div(T , T1 , L2). 这不是在Prolog中比较列表长度的方式。它比较“术语”length(L)和length(L1)而不进行解释,

我正在用Prolog编写一个谓词,将一个列表分成两个长度相等的列表。例如:

div([1,2,3,4] , X , Y).
X = [1,2].
Y = [3,4].
这是我的代码,但不起作用:

div(L , L1 , L):- length(L) == length(L1).
div([ H | T ] , [ H | T1] , L2):- div(T , T1 , L2).
这不是在Prolog中比较列表长度的方式。它比较“术语”
length(L)
length(L1)
而不进行解释,即不调用任何谓词。要比较长度,请执行以下操作:

length(L, N), length(L1, N)
如果您解决了这个问题,您的程序应该更接近正常工作。

可能只是:

div(L, A, B) :-
    append(A, B, L),
    length(A, N),
    length(B, N).

读作“将列表A和列表B添加到原始列表L中,A的长度是某个值N,B的长度也是相同的值N”

我喜欢Sergey的解决方案,因为它优雅简单(+1)。这里有另一种方法,它不那么优雅,有利于进一步提高效率,因为它删减了查询
append
的情况。如果
A
B
是地面,那么我们就让它们的长度来驱动这个过程。否则,我们让
L
的长度驱动它:

div(L, A, B) :-
    (   \+ground(A),
        \+ground(B)
    ->  length(L, N),
        HalfN is N div 2
    ;   true
    ),
    length(A, HalfN),
    length(B, HalfN),
    append(A, B, L).
这将产生,例如:

| ?-  div2(L, A, B).

A = []
B = []
L = [] ? ;

A = [C]
B = [D]
L = [C,D] ? ;

A = [C,D]
B = [E,F]
L = [C,D,E,F] ?
...

| ?- div([1,2,3|T], A, B).

A = [1,2]
B = [3,C]
T = [C] ? ;

A = [1,2,3]
B = [C,D,E]
T = [C,D,E] ? ;
...

| ?- div(L, [1,2], B).

B = [A,C]
L = [1,2,A,C]

yes
| ?- div([1,2|T], [1,2], [3,4]).

T = [3,4]

yes
| ?-

等等。

有趣的是,这种不使用长度的分割:

div(L, A, B) :-
    split(L, L, A, B).

split(B, [], [], B).

split([H|T], [_, _|T1], [H | T2], B) :-
    split(T, T1, T2, B).
对于一个包含100000个元素的列表,它使用50001个推断,但0016CPU,对于同一个列表,潜伏者的代码使用50015个推断和0000个CPU

div(L,L1,L2) :- length(L,Len), N is Len/2, split(L,L1,L2,N).
split([H|T],[H|L1],L2,N):- N1 is N-1, split(T,L1,L2,N1).
split(T,[],T,0).

就是这样,使用奇怪的长度:)

我编辑了它,但仍然没有工作:div(L,L1,L):-length(L,Q),length(L1,W),Q=:=W.div([H | t],[H | T1],L2):-div(t,T1,L2)。@user3100088他说你的程序将更接近工作状态。你能从那里找到答案吗?此外,您不需要
length(L,Q),length(L1,W),Q=:=W。
正如larsmans指出的那样,只要做
length(L,N),length(L1,N)
就足够了。一旦您解决了
length/2
的问题,您的解决方案似乎仍在尝试构建前半个列表,但它没有任何代码来处理下半场。您可能需要一个辅助谓词来处理长度计数器。或者,您可以考虑使用<代码>附件/3 。对于
div(L,X,Y)
查看
append(X,Y,L)
并约束
X
Y
的长度。稍短但其他方面相同:
div(L,A,B):-append(A,B,L),相同的长度(A,B)A
B
的长度,
div(L,A,B):-length(L,N),Half是N div 2,length(A,Half),length(B,Half),length(B,Half),append(A,B,L)。
或者更确切地说是O(N^2)vs O(N)。Sergey的代码有10000个元素的列表,30 006推断为0140 CPU,潜伏者的代码5015推断0000 CPU@SergeyDymchenko我喜欢你的解决方案(+1),它确实比我的建议更具关联性和优雅性。我认为当
L
是ungound,而
A
B
中的一个是ungound时,“更高效”版本唯一失败的关系案例。它给出了正确的解决方案,但在回溯更多解决方案时将永远旋转。它可能会被修改以避免这种情况。那么,这只是优雅与高效之间的权衡。当然,代码并不总是关于效率啊!你以14个推论击败了我!我预感有一个更优雅的解决方案。非常好(+1)。:)你的更快,什么是最有用的?因此
split/4
使用列表本身作为双倍递减的“计数器”,以避免使用
length/2
“最有用”很难判断,这取决于应用程序。在这种情况下,我们可能是在吹毛求疵。:)编码通常是简单性(提高清晰度和可维护性)和效率之间的平衡。我认为你的解决方案取得了很好的平衡。
div(L,L1,L2) :- length(L,Len), N is Len/2, split(L,L1,L2,N).
split([H|T],[H|L1],L2,N):- N1 is N-1, split(T,L1,L2,N1).
split(T,[],T,0).
div(L, A, B) :-
append(A, B, L),
length(A, O),
length(B, N),
((O-1)=:=N;(O+1)=:=N;O=:=N),
!.