Prolog:词典比较和拆分列表

时间:2016-06-06 02:19:26

标签: prolog

给定原子x,我试图将一个列表拆分成一个小于x的原子和一个原子等于或大于x的列表。

例如)

%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) should give me
%% AtomSmall = [a,b,c], AtomBig = [d,e,f]

以下是我迄今为止尝试过的内容。我得到了这个概念。但是我的代码包含了AtomSmall列表中x的等价原子,而不是AtomBig,尽管我在谓词之前检查了一下。 例如)

%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) gives me
%% AtomSmall = [a,b,c,d], AtomBig = [e,f]


before(X,Y):-atom_codes(X,A),atom_codes(Y,B),small(A,B).
small([],[]).
small([H1|T1],[H2|T2]):-H1<H2.
small([H1|T1],[H2|T2]):-H1=:=H2,small(T1,T2).

split(X,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-before(H1,X),split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):-not(before(H1,X)),split(X,T1,Small,Big).

请帮忙!

2 个答案:

答案 0 :(得分:0)

在SWI-Prolog中,您可以使用库中的partition / 4(列表)和标准订单比较(@&gt;)/ 2:

?- lists:partition(@>(d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].

由于比较中的参数顺序是固定的,将pivot作为第一个参数传递,因此lambda表达式(使用库(yall)需要最新版本)可以帮助提供更直观的读数:

?- partition([E]>>(E@<d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].

无论如何,您的代码可以像这样打补丁:

split(_,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-H1@<X,split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):- \+ H1@<X,split(X,T1,Small,Big).

?- split(d,[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f] ;
false.

答案 1 :(得分:0)

如果参数在字典上等效,则-i谓词会成功。例如,before/2为真。这是因为你的第3个子句在整个列表中允许相等的值,直到基本案例最终成功用两个空列表。

此外,如果before(a, a)before(X, Y)是不同长度的原子,X将会失败。例如,Y将失败。所以你的before(ab, abc)也需要照顾这个案例。

重构small/2将解决这个问题:

small/2

但是......你不需要通过% 1st clause is fixed so unequal length atoms are handled properly small([], _). small([H1|_], [H2|_]) :- H1 < H2. % 3rd clause is fixed so that equal atoms won't succeed here small([H,H1|T1], [H,H2|T2]) :- small([H1|T1], [H2|T2]). 完成所有这些操作。 Prolog知道如何使用before/2@<运算符以合理的方式比较原子(和一般的Prolog术语),正如@CapelliC在他的回答中指出的那样。所以你的@>就变成了:

before/2

你根本不需要before(X, Y) :- X @< Y. 。这基本上是@CapelliC在答案中表现出来的第二个解决方案。