Prolog:在列表列表中以整数拆分列表

时间:2014-11-22 13:27:26

标签: list recursion split prolog

我想将通过整数分隔的单词列表拆分为列表列表。

示例查询和预期结果:

?- separatewords([h,e,l,l,o,1,o,v,e,r,3,t,h,e,r,e], X).
X = [[h,e,l,l,o],[o,v,e,r],[t,h,e,r,e]].

我已经取得了以下成就: 将列表拆分为第一个整数之前的一个列表和第一个整数之后的一个列表:

带结果的示例查询:

?- take1word([h,e,l,l,o,1,o,v,e,r,3,t,h,e,r,e], X, Y).
X = [h,e,l,l,o], Y = [o,v,e,r,3,t,h,e,r,e].                 % OK

我的代码:

 take1word([H|T],[],T) :-
    integer(H).
 take1word([H|T],[H|Hs],Y) :-
    (  float(H), take1word(T,Hs,Y)
    ;  atom(H), take1word(T,Hs,Y)
    ).

对于分隔单词,我的代码如下:

 separatewords([],[]).
 separatewords([H|T],L) :-  separatewords(T,[take1word([H|T],)|L]).

结果只给了我false,但我不知道,我做错了什么。

2 个答案:

答案 0 :(得分:2)

take1word/3存在问题:如果列表中有整数,则会收到一个字,但不会使用最后一个字。您需要为其添加另一个基本子句:

take1word([], [], []).
take1word([H|T],[],T) :- integer(H).
take1word([H|T],[H|Hs],Y) :- float(H), take1word(T,Hs,Y); atom(H), take1word(T,Hs,Y).

现在您的separatewords/2将起作用:

separatewords([],[]).
separatewords(L, [W|T]) :- take1word(L,W,R), separatewords(R,T).

Demo.

答案 1 :(得分:2)

以下是您如何以逻辑上纯粹的方式进行的工作。

splitlistIf/3与改进型测试谓词integer_t/2结合使用!

integer_t(X,Truth) :- integer(X), !, Truth = true.
integer_t(X,Truth) :- nonvar(X),  !, Truth = false.
integer_t(X,true)  :- freeze(X,  integer(X)).
integer_t(X,false) :- freeze(X,\+integer(X)).

让我们看看他们两个都在行动!

?- Xs=[ h,e,l,l,o,1,o,v,e,r,3,t,h,e,r,e ], splitlistIf(integer_truth,Xs,Yss).
Xs  = [ h,e,l,l,o,1,o,v,e,r,3,t,h,e,r,e ],
Yss = [[h,e,l,l,o],[o,v,e,r],[t,h,e,r,e]]. % succeeds deterministically

由于实施是单调的,因此当我们使用非基础术语时可以安全地使用它。

考虑以下两个逻辑上等效的查询:在程序上,它们在目标Xs被证明时splitListIf(integer_t,Xs,Yss)中项目的实例化方面有所不同。

?- Xs = [_,_,_,_,_], Xs = [a,b,0,b,a], splitlistIf(integer_t,Xs,Yss).
Xs = [a,b,0,b,a], Yss = [[a,b],[b,a]].     % succeeds deterministically

?- Xs = [_,_,_,_,_], splitlistIf(integer_t,Xs,Yss), Xs = [a,b,0,b,a].
  Xs = [a,b,0,b,a], Yss = [[a,b],[b,a]]    % succeeds leaving behind choicepoint
; false.

实施足够聪明,只在必要时留下选择点。