在Prolog中获取从i到j的索引的原子列表

时间:2016-04-02 02:49:27

标签: list split prolog

我想根据给定的index_from i到index_to j从原子列表中获取原子列表。我尝试了很多次,但它并没有把我的名单归还给我,而是真的'以下是我的代码,我想念什么?如何获取输出列表而不是' true'。

% splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, INDEX_FROM, OUTPUTLIST).
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,LIST) :-
    INPUT_LIST = INPUT_LIST,
    S = S,
    INDEX_FROM =:= INDEX_TO + 1,
    write(LIST),
    LIST = LIST.
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO,S,LIST) :-
    INDEX_FROM < INDEX_TO + 1,
    nth0(INDEX_FROM, INPUT_LIST, ELEMENT),
    (  INDEX_FROM =:= S ->
    L = []
    ;   
    L = LIST
    ),
    IF is INDEX_FROM + 1,
    append([ELEMENT],L,NLIST),
    splitList(INPUT_LIST,IF,INDEX_TO,S,NLIST),
    !.

?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,3,0,L).
?- true.

My atom list: ['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],

if index_from is 1, index_to is 3, I am expecting a returned output_list:
['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT'] instead of a 'true', 

在我的基础案例中,&#39;写(LIST)确实写了预期的列表&#39;,有什么想法吗?

2 个答案:

答案 0 :(得分:3)

您可以在不使用剪切的情况下编写此类谓词。考虑一下您的谓词应该描述的内容:列表,开始,结束和当前位置的一些索引以及适合您的开始和结束索引的第一个列表的子列表。所以list_indices_sublist可能是一个好名字。现在考虑一下你可以拥有的案例:

如果当前位置和结束位置相同,则第一个列表的头部是子列表中的最后一个:

list_indices_sublist([X|_Xs],_Start,End,End,[X]).

如果当前位置在起始位置和结束位置之间,则第一个列表的头部位于子列表中。对于两个列表的尾部,关系(=谓词)也必须保持(=递归):

list_indices_sublist([X|Xs],Start,End,Pos,[X|Zs]) :-
    Pos #>= Start,
    Pos #< End,
    Nextpos #= Pos + 1,
    list_indices_sublist(Xs,Start,End,Nextpos,Zs).

如果当前位置小于开始位置,则列表的头部不在子列表中。对于尾部,与上面相同:

list_indices_sublist([X|Xs],Start,End,Pos,Zs) :-
    Pos #< Start,
    Nextpos #= Pos+1,
    list_indices_sublist(Xs,Start,End,Nextpos,Zs).

您可能还会考虑提供一个更清晰的界面来隐藏代表列表中当前位置的辅助变量。对于应该适用于list_indices_sublist / 5的所有三个规则的约束,例如,这样的谓词也是一个好的地方。起始索引必须小于或等于结束索引。让我们调用这个谓词list_sublist_from_to / 4。把它们放在一起:

:- use_module(library(clpfd)).


list_sublist_from_to(L,S,Start,End) :-
    Start #=< End,
    list_indices_sublist(L,Start,End,1,S).

list_indices_sublist([X|_Xs],_Start,End,End,[X]).
list_indices_sublist([X|Xs],Start,End,Pos,[X|Zs]) :-
    Pos #>= Start,
    Pos #< End,
    Nextpos #= Pos + 1,
    list_indices_sublist(Xs,Start,End,Nextpos,Zs).
list_indices_sublist([X|Xs],Start,End,Pos,Zs) :-
    Pos #< Start,
    Nextpos #= Pos+1,
    list_indices_sublist(Xs,Start,End,Nextpos,Zs).

关于您提供的示例:您的意思是1到4,对吧?

?- list_sublist_from_to(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'] ,L,1,4).
L = ['TYPE_INT','IDENTIFIER','OPEN_P','TYPE_INT'] ? ;
no

或1到3以及子列表中包含3个元素的答案:

list_sublist_from_to(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'] ,L,1,3).
L = ['TYPE_INT','IDENTIFIER','OPEN_P'] ? ;
no 

注意:如果你想用0而不是1开始计算你的列表位置,只需在list_sublist_from_to / 4的第二个目标中将1更改为0

答案 1 :(得分:1)

首先,您应该注意Prolog不是基于作业,而是基于统一。然后,例如,

INPUT_LIST = INPUT_LIST,

是一种重言式(将相同的术语与自身统一起来,总是如此)。你可以安全地删除它们。

其次,您的代码有一个额外的参数S,没有明确的作用。可能是您尝试实现的剩余细节,但它应该真正“隐藏”,例如:

% splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, OUTPUTLIST).
splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, LIST) :-
  splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, 0, LIST).

第三,谓词最后一个句子末尾的减少是完全没用的,因为所有的选择都已经尝试过 - 成功了。什么都没有被削减......

第四,既然你使用内置的nth0 / 3,那么请注意一个更简单的实现可能

splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, LIST) :-
  findall(E, (between(INDEX_FROM,INDEX_TO,I),nth0(I,INPUT_LIST,E)), LIST).

?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,3,L).
L = ['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT'].

但是我们试着纠正你的代码。可能是

splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, LIST) :-
  splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, 0, LIST).

splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,LIST) :-
  S < INDEX_FROM,
  S1 is S+1,
  splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S1,LIST).
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,[ELEMENT|LIST]) :-
  S >= INDEX_FROM, S =< INDEX_TO,
  nth0(S, INPUT_LIST, ELEMENT),
  S1 is S+1,
  splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S1,LIST).
splitList(_INPUT_LIST,_INDEX_FROM,INDEX_TO, S,[]) :-
  S > INDEX_TO.

并将获得与上面列出的基于findall / 3的单线程相似的结果。请注意,ELEMENT不是使用append / 3,而是'consed'进入'output'参数。看看你是否能发现这段代码固有的问题,具体来说,试着理解为什么

?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,10,L).
false.